docs: dịch 22 file Markdown còn lại sang tiếng Việt có dấu (TEC-2881)
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 18s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 2m15s
Deploy / Build API Image (push) Failing after 28s
Deploy / Build Web Image (push) Failing after 16s
Deploy / Build AI Services Image (push) Failing after 17s
E2E Tests / Playwright E2E (push) Failing after 31s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 1m46s
Security Scanning / Trivy Scan — Web Image (push) Failing after 1m7s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 53s
Security Scanning / Trivy Filesystem Scan (push) Failing after 35s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 0s
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped

Hoàn tất đợt cuối của nhiệm vụ chuyển toàn bộ tài liệu sang tiếng Việt.
Đã dịch 22 file `.md` còn sót (~9.7k dòng) — gồm RUNBOOK, audits,
docs/architecture, docs/load-testing, libs READMEs và các quick references.
Giữ nguyên code blocks, đường dẫn, identifier kỹ thuật, URL và biến môi trường.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Ho Ngoc Hai
2026-04-19 03:26:14 +07:00
parent 11f2bf26e6
commit d8b409a9ab
22 changed files with 3697 additions and 3703 deletions

View File

@@ -1,16 +1,16 @@
# GoodGo Frontend: File-by-File i18n & A11y Implementation Guide
# GoodGo Frontend: Hướng dẫn triển khai i18n & A11y theo từng file
## 📋 Complete File Mapping
## 📋 Ánh xạ file đầy đủ
### PHASE 1: INFRASTRUCTURE SETUP
### GIAI ĐOẠN 1: THIẾT LẬP HẠ TẦNG
#### 1. `middleware.ts` (CRITICAL)
**Current:** Auth routing only
**Changes:**
- Add locale detection from URL pathname
- Add cookie-based locale storage
- Redirect `/en/*` and `/vi/*` paths appropriately
- Add Accept-Language header fallback
#### 1. `middleware.ts` (QUAN TRỌNG)
**Hiện tại:** Chỉ định tuyến xác thực
**Thay đổi:**
- Thêm phát hiện locale từ pathname URL
- Thêm lưu trữ locale dựa trên cookie
- Chuyển hướng các đường dẫn `/en/*` `/vi/*` một cách phù hợp
- Thêm dự phòng dựa trên header Accept-Language
**Pseudo-code:**
```typescript
@@ -32,15 +32,15 @@ export function middleware(request: NextRequest) {
}
```
#### 2. `app/layout.tsx` (CRITICAL)
**Current:** Thai providers, hardcoded Vietnamese metadata
**Changes:**
- Change `lang="vi"` to dynamic locale
- Update metadata to be i18n-aware
- Wrap with `NextIntlClientProvider` from next-intl
- Keep existing providers (ThemeProvider, QueryProvider, AuthProvider)
#### 2. `app/layout.tsx` (QUAN TRỌNG)
**Hiện tại:** Các provider chính, metadata tiếng Việt được hardcode
**Thay đổi:**
- Thay đổi `lang="vi"` thành locale động
- Cập nhật metadata để hỗ trợ i18n
- Bao bọc bằng `NextIntlClientProvider` từ next-intl
- Giữ nguyên các provider hiện có (ThemeProvider, QueryProvider, AuthProvider)
**Key changes:**
**Các thay đổi chính:**
```typescript
import { getLocale, getTranslations } from 'next-intl/server';
@@ -59,8 +59,8 @@ export async function generateMetadata(): Promise<Metadata> {
}
```
#### 3. `i18n/config.ts` (NEW)
**Create new file** with i18n configuration:
#### 3. `i18n/config.ts` (MỚI)
**Tạo file mới** với cấu hình i18n:
```typescript
export const locales = ['en', 'vi'] as const;
export const defaultLocale = 'vi';
@@ -68,8 +68,8 @@ export const defaultLocale = 'vi';
export const timeZone = 'Asia/Ho_Chi_Minh';
```
#### 4. `public/locales/en.json` (NEW - LARGE FILE)
**Structure:**
#### 4. `public/locales/en.json` (MỚI - FILE LỚN)
**Cấu trúc:**
```json
{
"common": {
@@ -179,16 +179,16 @@ export const timeZone = 'Asia/Ho_Chi_Minh';
}
```
#### 5. `public/locales/vi.json` (NEW - LARGE FILE)
Same structure as en.json but with Vietnamese translations.
#### 5. `public/locales/vi.json` (MỚI - FILE LỚN)
Cấu trúc giống en.json nhưng với bản dịch tiếng Việt.
---
### PHASE 2: CORE COMPONENT UPDATES
### GIAI ĐOẠN 2: CẬP NHẬT COMPONENT CỐT LÕI
#### Files Requiring Translation Hook Integration
#### Các file cần tích hợp Translation Hook
##### Layout Files
##### Các file Layout
1. **`app/(public)/layout.tsx`**
```typescript
@@ -220,20 +220,20 @@ const toggleLabel = theme === 'light'
```
3. **`app/(auth)/layout.tsx`**
Update any error messages or labels to use translations.
Cập nhật mọi thông báo lỗi hoặc nhãn để sử dụng bản dịch.
##### Page Files
##### Các file Page
1. **`app/(public)/page.tsx` (LARGE FILE)**
**Areas to update:**
- Hero section (title, subtitle)
- Search form (placeholder)
- Property type badges
- Price ranges
- City options
- Section headings
- Stats labels
- CTA buttons
1. **`app/(public)/page.tsx` (FILE LỚN)**
**Các phần cần cập nhật:**
- Phần hero (tiêu đề, phụ đề)
- Form tìm kiếm (placeholder)
- Các badge loại bất động sản
- Các khoảng giá
- Tùy chọn thành phố
- Tiêu đề các phần
- Nhãn thống kê
- Các nút CTA
```typescript
export default function LandingPage() {
@@ -268,32 +268,32 @@ const OAUTH_ERROR_MESSAGES = {
```
3. **`app/(auth)/register/page.tsx`**
Same pattern as login page.
Tương tự như trang login.
4. **`app/(dashboard)/dashboard/page.tsx`** and all other dashboard pages
Update section titles, empty states, button labels.
4. **`app/(dashboard)/dashboard/page.tsx`** và tất cả các trang dashboard khác
Cập nhật tiêu đề các phần, trạng thái rỗng, nhãn các nút.
##### Search & Listing Pages
##### Các trang Search & Listing
1. **`app/(public)/search/page.tsx`**
Update search results headings, empty states, filter labels.
Cập nhật tiêu đề kết quả tìm kiếm, trạng thái rỗng, nhãn bộ lọc.
2. **`app/(public)/listings/[id]/page.tsx`**
Update property detail labels.
Cập nhật nhãn chi tiết bất động sản.
3. **`app/(dashboard)/listings/page.tsx`**
Update table headers, status labels, action labels.
Cập nhật tiêu đề bảng, nhãn trạng thái, nhãn hành động.
4. **`app/(dashboard)/listings/new/page.tsx`**
Uses listing-form-steps component (see below).
Sử dụng component listing-form-steps (xem bên dưới).
---
#### Component Files
#### Các file Component
##### Critical Components (Do First)
##### Các component quan trọng (Làm trước)
1. **`components/search/filter-bar.tsx` (HIGH PRIORITY)**
1. **`components/search/filter-bar.tsx` (ƯU TIÊN CAO)**
```typescript
// Current: Hardcoded arrays
const CITIES = ['Hồ Chí Minh', 'Hà Nội', 'Đà Nẵng', ...];
@@ -310,14 +310,14 @@ const PRICE_RANGES = [
];
```
2. **`components/listings/listing-form-steps.tsx` (HIGH PRIORITY - LARGE FILE)**
This multi-step form has many labels to translate:
- Step 1: Transaction type, property type, title, description
- Step 2: Address fields, location
- Step 3: Area, rooms, bathrooms, direction, year built, etc.
- Step 4: Pricing
2. **`components/listings/listing-form-steps.tsx` (ƯU TIÊN CAO - FILE LỚN)**
Form đa bước này có nhiều nhãn cần dịch:
- Bước 1: Loại giao dịch, loại bất động sản, tiêu đề, mô tả
- Bước 2: Các trường địa chỉ, vị trí
- Bước 3: Diện tích, phòng, phòng tắm, hướng, năm xây dựng, v.v.
- Bước 4: Giá
All field labels should use `t('form.field_name')` pattern.
Tất cả nhãn các trường nên sử dụng pattern `t('form.field_name')`.
3. **`components/auth/oauth-buttons.tsx`**
```typescript
@@ -330,7 +330,7 @@ All field labels should use `t('form.field_name')` pattern.
</Button>
```
##### Medium Priority Components
##### Các component ưu tiên trung bình
1. **`components/search/property-card.tsx`**
```typescript
@@ -361,21 +361,21 @@ const LISTING_STATUSES = {
```
3. **`components/valuation/valuation-form.tsx`**
Update form labels and buttons.
Cập nhật nhãn form và các nút.
4. **`components/listings/image-upload.tsx`**
Update button text and error messages.
Cập nhật văn bản nút và thông báo lỗi.
5. **All `components/ui/*.tsx` files with text**
- Button: any default text
- Dialog: Close button aria-label
- Input: placeholder attrs if hardcoded
- Label: any default text
- Others: similar
5. **Tất cả các file `components/ui/*.tsx` có văn bản**
- Button: bất kỳ văn bản mặc định nào
- Dialog: aria-label nút Đóng
- Input: thuộc tính placeholder nếu được hardcode
- Label: bất kỳ văn bản mặc định nào
- Khác: tương tự
---
### PHASE 3: VALIDATION & ERROR MESSAGES
### GIAI ĐOẠN 3: VALIDATION & THÔNG BÁO LỖI
#### 1. `lib/validations/auth.ts`
```typescript
@@ -394,21 +394,21 @@ const schema = z.object({
});
```
#### 2. `lib/validations/listings.ts` (LARGE FILE)
Update all Zod validation error messages:
#### 2. `lib/validations/listings.ts` (FILE LỚN)
Cập nhật tất cả thông báo lỗi validation Zod:
- "Vui lòng chọn loại giao dịch" → `t('validation.transaction_required')`
- "Tiêu đề tối thiểu 5 ký tự" → `t('validation.title_min_length')`
- All other validation messages
- Tất cả các thông báo validation khác
#### 3. `lib/validations/valuation.ts`
Similar pattern to listings.
Mẫu tương tự như listings.
---
### PHASE 4: UTILITY UPDATES
### GIAI ĐOẠN 4: CẬP NHẬT TIỆN ÍCH
#### 1. `lib/utils.ts`
No changes (already minimal).
Không thay đổi (đã tối giản).
#### 2. `lib/auth-store.ts`
```typescript
@@ -417,17 +417,17 @@ No changes (already minimal).
```
#### 3. `lib/api-client.ts`
Check if error messages from API need i18n wrapping.
Kiểm tra xem các thông báo lỗi từ API có cần bao bọc i18n hay không.
#### 4. All `lib/*-api.ts` files
Update error message handling if needed.
#### 4. Tất cả các file `lib/*-api.ts`
Cập nhật xử lý thông báo lỗi nếu cần.
---
### PHASE 5: ACCESSIBILITY UPDATES
### GIAI ĐOẠN 5: CẬP NHẬT KHẢ NĂNG TIẾP CẬN
#### 1. `components/ui/dialog.tsx` (CRITICAL A11y)
**Add focus management:**
#### 1. `components/ui/dialog.tsx` (A11y QUAN TRỌNG)
**Thêm quản lý focus:**
```typescript
// Add focus trap
// Save initial focus element
@@ -466,7 +466,7 @@ function Dialog() {
```
#### 2. `components/ui/input.tsx`
Add aria-describedby for error messages:
Thêm aria-describedby cho thông báo lỗi:
```typescript
export function Input({ error, ...props }) {
const errorId = `${props.id}-error`;
@@ -484,8 +484,8 @@ export function Input({ error, ...props }) {
```
#### 3. `components/ui/button.tsx`
Ensure all buttons have visible focus indicator (already in CSS likely).
Add aria-busy for loading state if used:
Đảm bảo tất cả các nút có chỉ báo focus rõ ràng (có thể đã có trong CSS).
Thêm aria-busy cho trạng thái loading nếu được sử dụng:
```typescript
export function Button({ disabled, isLoading, ...props }) {
return (
@@ -500,15 +500,15 @@ export function Button({ disabled, isLoading, ...props }) {
}
```
#### 4. Form Components
Update all forms to use aria-describedby for error messages:
- `app/(auth)/login/page.tsx`Already has role="alert" ✓ but could use aria-describedby
- `app/(auth)/register/page.tsx`Same
- `components/listings/listing-form-steps.tsx`Add aria-describedby
- `components/search/filter-bar.tsx`Ensure accessible labels
#### 4. Các component Form
Cập nhật tất cả các form để sử dụng aria-describedby cho thông báo lỗi:
- `app/(auth)/login/page.tsx`Đã có role="alert" ✓ nhưng có thể dùng aria-describedby
- `app/(auth)/register/page.tsx`Tương tự
- `components/listings/listing-form-steps.tsx`Thêm aria-describedby
- `components/search/filter-bar.tsx`Đảm bảo nhãn dễ tiếp cận
#### 5. All Icon-Only Buttons
Find all buttons with only icons and add aria-label:
#### 5. Tất cả các nút chỉ có biểu tượng
Tìm tất cả các nút chỉ có biểu tượng và thêm aria-label:
```typescript
// Search in components for: <Button> with only SVG children
// Add aria-label={t('...')}
@@ -524,7 +524,7 @@ Find all buttons with only icons and add aria-label:
```
#### 6. Loading Spinners
Add aria-busy and aria-label:
Thêm aria-busy aria-label:
```typescript
// In app/(public)/page.tsx and similar:
<div aria-busy={loadingFeatured} aria-label={t('common.loading')}>
@@ -533,7 +533,7 @@ Add aria-busy and aria-label:
```
#### 7. `components/listings/image-gallery.tsx`
Add keyboard navigation (arrow keys):
Thêm điều hướng bằng bàn phím (phím mũi tên):
```typescript
// Add keyboard event handler for arrow keys
// Left/Right arrows to navigate images
@@ -541,7 +541,7 @@ Add keyboard navigation (arrow keys):
---
### PHASE 6: TEST SETUP UPDATES
### GIAI ĐOẠN 6: CẬP NHẬT THIẾT LẬP TEST
#### 1. `vitest.setup.ts`
```typescript
@@ -564,35 +564,35 @@ vi.mock('next-intl', () => ({
```
#### 2. `vitest.config.ts`
May need to add path aliases or test environment setup.
Có thể cần thêm path alias hoặc thiết lập môi trường test.
#### 3. Update all test files in `__tests__/` folders
- Add locale prop to component renders
- Test both English and Vietnamese if applicable
- Mock i18n translations
#### 3. Cập nhật tất cả các file test trong thư mục `__tests__/`
- Thêm prop locale khi render component
- Test cả tiếng Anh và tiếng Việt nếu có thể
- Mock các bản dịch i18n
---
## 📊 Summary: Files by Update Complexity
## 📊 Tóm tắt: Các file theo độ phức tạp cập nhật
### Trivial (5 min each)
### Đơn giản (5 phút mỗi file)
- `app/robots.ts`
- `app/sitemap.ts`
- `components/ui/badge.tsx`
- `components/ui/card.tsx`
- `components/ui/tabs.tsx`
### Simple (15-30 min each)
- `app/(admin)/*.tsx` files (3 files)
### Đơn giản (15-30 phút mỗi file)
- Các file `app/(admin)/*.tsx` (3 file)
- `app/(dashboard)/analytics/page.tsx`
- `app/(dashboard)/profile/page.tsx`
- `app/(dashboard)/subscription/page.tsx`
- `app/(dashboard)/payments/page.tsx`
- `components/ui/*.tsx` (8 files)
- `components/ui/*.tsx` (8 file)
- `components/auth/oauth-buttons.tsx`
- `components/listings/listing-status-badge.tsx`
### Medium (30-60 min each)
### Trung bình (30-60 phút mỗi file)
- `app/(public)/layout.tsx`
- `app/(auth)/login/page.tsx`
- `app/(auth)/register/page.tsx`
@@ -602,47 +602,47 @@ May need to add path aliases or test environment setup.
- `components/search/property-card.tsx`
- `components/search/filter-bar.tsx`
- `components/listings/image-upload.tsx`
- `components/valuation/*.tsx` (3 files)
- `components/valuation/*.tsx` (3 file)
### Complex (1-2 hours each)
- `app/(public)/page.tsx` (landing page - many sections)
- `components/listings/listing-form-steps.tsx` (multi-step form)
- `components/map/listing-map.tsx` (if has labels)
- `components/charts/*.tsx` (3 files - chart labels)
### Phức tạp (1-2 giờ mỗi file)
- `app/(public)/page.tsx` (trang landing - nhiều phần)
- `components/listings/listing-form-steps.tsx` (form đa bước)
- `components/map/listing-map.tsx` (nếu có nhãn)
- `components/charts/*.tsx` (3 file - nhãn biểu đồ)
### Critical Infrastructure
- `middleware.ts` (30-45 min)
- `app/layout.tsx` (30 min)
- `lib/validations/*.ts` (3 files - 45 min)
### Hạ tầng quan trọng
- `middleware.ts` (30-45 phút)
- `app/layout.tsx` (30 phút)
- `lib/validations/*.ts` (3 file - 45 phút)
---
## ✅ Validation Checklist
## ✅ Checklist xác minh
Before considering i18n + A11y complete:
Trước khi xem xét i18n + A11y hoàn tất:
### i18n Verification
- [ ] Both `/en/*` and `/vi/*` routes work
- [ ] All text from messages files, not hardcoded
- [ ] Metadata changes with locale
- [ ] Cookies/headers work for locale selection
- [ ] Validation messages use i18n
- [ ] All enums use translations
- [ ] Tests mock i18n correctly
### Xác minh i18n
- [ ] Cả route `/en/*` `/vi/*` đều hoạt động
- [ ] Tất cả văn bản từ file messages, không hardcode
- [ ] Metadata thay đổi theo locale
- [ ] Cookie/header hoạt động cho việc chọn locale
- [ ] Thông báo validation sử dụng i18n
- [ ] Tất cả các enum sử dụng bản dịch
- [ ] Test mock i18n đúng cách
### A11y Verification
- [ ] Focus trap works in dialogs
- [ ] Focus indicator visible on all inputs
- [ ] Form errors linked with aria-describedby
- [ ] Icon buttons all have aria-labels
- [ ] Color contrast >= 4.5:1 for text (AA standard)
- [ ] Keyboard navigation works everywhere
- [ ] Screen reader testing (NVDA/JAWS)
- [ ] Loading spinners have aria-busy
- [ ] All tables have proper headers
### Xác minh A11y
- [ ] Focus trap hoạt động trong dialog
- [ ] Chỉ báo focus hiển thị trên tất cả input
- [ ] Lỗi form được liên kết với aria-describedby
- [ ] Tất cả nút biểu tượng có aria-label
- [ ] Tỷ lệ tương phản màu >= 4.5:1 cho văn bản (chuẩn AA)
- [ ] Điều hướng bàn phím hoạt động ở mọi nơi
- [ ] Test với screen reader (NVDA/JAWS)
- [ ] Loading spinner aria-busy
- [ ] Tất cả các bảng có header phù hợp
---
**Generated:** April 9, 2026
**Confidence:** High
**Total Estimated Files to Update:** 50-60 files
**Được tạo:** Ngày 9 tháng 4 năm 2026
**Độ tin cậy:** Cao
**Tổng số file ước tính cần cập nhật:** 50-60 file