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
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:
@@ -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/*` và `/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 và 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/*` và `/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 có 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
|
||||
|
||||
Reference in New Issue
Block a user