---
name: i18n-workflow
description: 多語言國際化開發流程與規範
license: MIT
compatibility: opencode
metadata:
audience: developers
workflow: internationalization
---
## 我的功能
- 提供多語言開發的標準化流程
- 確保五種語言 (繁中、簡中、英、日、韓) 的一致性
- 管理翻譯檔案的新增、更新和維護
- 協助實現語言持久化和即時切換
## 何時使用我
在以下情況下使用此技能:
- 新增使用者可見的文字或訊息時
- 修改現有文字內容時
- 新增新功能需要多語言支援
- 檢查翻譯完整性和一致性
- 設定語言切換功能
## 支援語言
本專案支援五種語言:
- **繁體中文 (zh-TW)** - 預設語言
- **簡體中文 (zh-CN)**
- **英文 (en)**
- **日文 (ja)**
- **韓文 (ko)**
## 檔案結構
```
src/i18n/
├── config.ts # i18next 配置
└── locales/
├── zh-TW.json # 繁體中文(預設)
├── zh-CN.json # 簡體中文
├── en.json # 英文
├── ja.json # 日文
└── ko.json # 韓文
```
## 使用 i18next
### 在元件中使用
```typescript
'use client';
import { useTranslation } from 'react-i18next';
export default function Component() {
const { t } = useTranslation();
return (
{t('common.appName')}
{t('stats.speed')}
);
}
```
### 語言切換
```typescript
'use client';
import { useTranslation } from 'react-i18next';
import { useAtom } from 'jotai';
import { languageAtom } from '@/store/dataAtoms';
export default function LanguageSelector() {
const { i18n } = useTranslation();
const [language, setLanguage] = useAtom(languageAtom);
const handleLanguageChange = (lang: string) => {
i18n.changeLanguage(lang);
setLanguage(lang as SupportedLanguage);
};
return (
);
}
```
## 新增翻譯流程
### 重要原則
⚠️ **必須同時更新所有五個語言檔案**
每次新增或修改翻譯時,必須確保所有語言檔案都有對應的翻譯內容。
### 步驟
#### 1. 確定翻譯 Key 結構
使用點號分隔的命名空間結構:
```
category.subcategory.key
```
範例:
- `common.appName` - 通用類別的應用程式名稱
- `stats.speed` - 統計類別的速度
- `actions.save` - 動作類別的儲存
#### 2. 在所有語言檔案中新增翻譯
```json
// zh-TW.json
{
"newFeature": {
"title": "新功能標題",
"description": "新功能說明",
"button": "確認"
}
}
// zh-CN.json
{
"newFeature": {
"title": "新功能标题",
"description": "新功能说明",
"button": "确认"
}
}
// en.json
{
"newFeature": {
"title": "New Feature Title",
"description": "New feature description",
"button": "Confirm"
}
}
// ja.json
{
"newFeature": {
"title": "新機能タイトル",
"description": "新機能の説明",
"button": "確認"
}
}
// ko.json
{
"newFeature": {
"title": "새 기능 제목",
"description": "새 기능 설명",
"button": "확인"
}
}
```
#### 3. 在元件中使用
```typescript
'use client';
import { useTranslation } from 'react-i18next';
export default function NewFeature() {
const { t } = useTranslation();
return (
{t('newFeature.title')}
{t('newFeature.description')}
);
}
```
## 翻譯檔案結構規範
### 命名空間分類
```json
{
"common": {
"appName": "應用程式名稱",
"loading": "載入中...",
"error": "錯誤訊息"
},
"navigation": {
"home": "首頁",
"about": "關於",
"settings": "設定"
},
"stats": {
"speed": "速度",
"acceleration": "加速度",
"weight": "重量",
"handling": "操控性"
},
"actions": {
"save": "儲存",
"cancel": "取消",
"confirm": "確認",
"delete": "刪除"
},
"messages": {
"success": "操作成功",
"error": "操作失敗",
"warning": "警告訊息"
}
}
```
### 保持結構一致
所有語言檔案必須保持相同的 JSON 結構:
```json
// ✅ 正確 - 所有語言有相同的 key
// zh-TW.json
{
"user": {
"profile": "個人資料",
"settings": "設定"
}
}
// en.json
{
"user": {
"profile": "Profile",
"settings": "Settings"
}
}
// ❌ 錯誤 - 結構不一致
// zh-TW.json
{
"user": {
"profile": "個人資料",
"settings": "設定"
}
}
// en.json
{
"user": {
"profile": "Profile"
// 缺少 settings
}
}
```
## 語言持久化
### 使用 Jotai atomWithStorage
```typescript
// store/dataAtoms.ts
import { atomWithStorage } from "jotai/utils";
export const languageAtom = atomWithStorage(
"mario-kart-language",
"zh-TW",
);
```
### 語言持久化 Hook
```typescript
// hooks/useLanguagePersistence.ts
"use client";
import { useEffect } from "react";
import { useAtom } from "jotai";
import { useTranslation } from "react-i18next";
import { languageAtom } from "@/store/dataAtoms";
export function useLanguagePersistence() {
const [language] = useAtom(languageAtom);
const { i18n } = useTranslation();
useEffect(() => {
if (language && i18n.language !== language) {
i18n.changeLanguage(language);
}
}, [language, i18n]);
}
```
## 翻譯品質原則
### 1. 準確性
- 翻譯必須準確傳達原意
- 避免使用機器翻譯的生硬表達
- 符合目標語言的語言習慣
### 2. 一致性
- 相同概念使用相同翻譯
- 建立專案術語表
- 統一專有名詞的翻譯
### 3. 簡潔性
- 避免冗長的翻譯
- 使用簡潔清晰的表達
- 考慮 UI 空間限制
### 4. 文化適應
- 考慮不同文化背景
- 避免文化敏感內容
- 適應當地使用習慣
## 動態翻譯
### 帶參數的翻譯
```json
// zh-TW.json
{
"greeting": "你好,{{name}}!",
"itemCount": "共 {{count}} 個項目"
}
```
```typescript
// 使用
const { t } = useTranslation();
{t('greeting', { name: '使用者' })}
{t('itemCount', { count: 10 })}
```
### 複數形式處理
```json
// en.json
{
"items": "{{count}} item",
"items_other": "{{count}} items"
}
```
```typescript
const { t } = useTranslation();
{t('items', { count: 1 })}
// "1 item"
{t('items', { count: 5 })}
// "5 items"
```
## 檢查清單
在提交翻譯前,請確認:
- [ ] 所有五個語言檔案都已更新
- [ ] JSON 格式正確,沒有語法錯誤
- [ ] 所有語言檔案結構一致
- [ ] 翻譯準確且符合語言習慣
- [ ] 使用 `t()` 函式而非硬編碼文字
- [ ] 語言切換功能正常運作
- [ ] localStorage 正確儲存語言設定
- [ ] 測試所有語言的顯示效果
## 常見問題
### Q: 如何處理長文字翻譯?
A: 將長文字拆分為多個 key,或使用換行符號:
```json
{
"longText": "這是第一段文字。\n這是第二段文字。"
}
```
### Q: 如何處理 HTML 標籤?
A: 使用 `Trans` 組件:
```typescript
import { Trans } from 'react-i18next';
This is bold text.
```
### Q: 如何確保翻譯完整性?
A: 建立自動化腳本檢查所有語言檔案是否有相同的 key 結構。
### Q: 如何處理圖片中的文字?
A: 為不同語言準備不同的圖片,根據當前語言動態載入。
## 測試流程
### 1. 手動測試
```bash
# 啟動開發伺服器
pnpm dev
# 測試步驟:
1. 切換到每種語言
2. 檢查所有頁面的文字顯示
3. 確認語言設定被正確儲存
4. 重新載入頁面確認語言保持
```
### 2. JSON 格式驗證
```bash
# 使用 JSON linter 檢查語法
pnpm lint
```
### 3. 翻譯覆蓋率檢查
建立腳本檢查所有語言檔案的 key 是否一致:
```typescript
// scripts/check-i18n.ts
const fs = require("fs");
const languages = ["zh-TW", "zh-CN", "en", "ja", "ko"];
const locales = {};
languages.forEach((lang) => {
locales[lang] = JSON.parse(
fs.readFileSync(`src/i18n/locales/${lang}.json`, "utf-8"),
);
});
// 檢查 key 一致性
// ... 實作邏輯
```
## 最佳實踐
### 1. 早期國際化
從專案開始就使用 `t()` 函式,避免後期大規模重構。
### 2. 翻譯文件化
建立翻譯指南文件,說明專案特定的術語翻譯。
### 3. 版本控制
使用 Git 追蹤翻譯檔案變更,便於審查和回溯。
### 4. 團隊協作
- 指定語言負責人審核翻譯
- 使用 Pull Request 審查翻譯變更
- 建立翻譯討論群組
### 5. 持續優化
- 收集使用者反饋
- 定期審查和優化翻譯
- 保持翻譯與功能同步更新
## 參考資源
- [i18next 官方文件](https://www.i18next.com/)
- [react-i18next 文件](https://react.i18next.com/)
- [Google 國際化指南](https://developers.google.com/international/)
- [W3C 國際化最佳實踐](https://www.w3.org/International/)