β
β β
β Translation resolves: β
β - t('dashboard.title') β "Panel de Control" (Spanish) β
β - t('common.save') β "Guardar" β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
\`\`\`
---
## Root Cause Summary
### What Works β
1. Language selection UI (LanguageSelector)
2. State management (LanguageContext)
3. localStorage persistence
4. i18next configuration
5. Translation files (complete with 132+ keys each)
6. React Context provider hierarchy
### What's Broken β
1. **ZERO components import \`useTranslation\` from react-i18next**
- Only found in: LanguageContext.tsx (infrastructure) and test files
- Not found in: Any page, layout, or UI component
2. **ZERO components call \`t()\` function to get translations**
- All text is hardcoded in JSX
- Example: \`
Dashboard
\` instead of \`
{t('dashboard.title')}
\`
3. **Navigation menu is entirely hardcoded**
- Layout.tsx has 20+ navigation items with English labels
---
## Translation Key Naming Convention
### Standard Structure
All translation keys follow a hierarchical namespace structure:
```
{category}.{subcategory}.{descriptor}
```
### Category Guidelines
| Category | Purpose | Example Keys |
|----------|---------|--------------|
| `common` | Shared UI elements used across multiple pages | `common.save`, `common.cancel` |
| `navigation` | Top-level navigation menu items | `navigation.dashboard`, `navigation.proxyHosts` |
| `{page}` | Page-specific content (dashboard, proxyHosts, etc.) | `proxyHosts.title`, `dashboard.description` |
| `errors` | Error messages and validation | `errors.required`, `errors.invalidEmail` |
| `notifications` | Toast/alert messages | `notifications.saveSuccess` |
| `auth` | Authentication and authorization | `auth.login`, `auth.logout` |
### Naming Rules
1. **Use camelCase** for all keys: `proxyHosts`, not `proxy-hosts` or `proxy_hosts`
2. **Be specific but concise**: `proxyHosts.addHost` not `proxyHosts.addNewProxyHost`
3. **Avoid abbreviations** unless universally understood: `smtp` (OK), `cfg` (avoid, use `config`)
4. **Group related keys** under same parent: `dashboard.activeHosts`, `dashboard.activeServers`
### Special Patterns
#### Pluralization
Use ICU MessageFormat for plurals:
```json
{
"proxyHosts": {
"count": "{{count}} proxy host",
"count_plural": "{{count}} proxy hosts",
"selectedCount": "{{count}} selected",
"selectedCount_plural": "{{count}} selected"
}
}
```
**Usage:**
```tsx
t('proxyHosts.count', { count: 1 }) // "1 proxy host"
t('proxyHosts.count', { count: 5 }) // "5 proxy hosts"
```
#### Dynamic Interpolation
Use `{{variableName}}` for dynamic content:
```json
{
"dashboard": {
"activeHosts": "{{count}} active",
"welcomeUser": "Welcome back, {{userName}}!",
"lastSync": "Last synced {{time}}"
}
}
```
**Usage:**
```tsx
t('dashboard.welcomeUser', { userName: 'Alice' }) // "Welcome back, Alice!"
```
#### Context Variants
For gender or context-specific translations:
```json
{
"common": {
"delete": "Delete",
"delete_male": "Delete (m)",
"delete_female": "Delete (f)",
"save_short": "Save",
"save_long": "Save Changes"
}
}
```
**Usage:**
```tsx
t('common.delete', { context: 'male' }) // Uses delete_male
t('common.save', { context: 'short' }) // Uses save_short
```
#### Nested Keys
Maximum 3 levels deep for maintainability:
```json
{
"security": {
"headers": {
"csp": "Content Security Policy",
"hsts": "HTTP Strict Transport Security"
},
"waf": {
"enabled": "WAF Enabled",
"rulesets": "Active Rulesets"
}
}
}
```
**Usage:**
```tsx
t('security.headers.csp') // "Content Security Policy"
```
#### Boolean States
Use consistent naming for on/off states:
```json
{
"common": {
"enabled": "Enabled",
"disabled": "Disabled",
"active": "Active",
"inactive": "Inactive",
"on": "On",
"off": "Off"
}
}
```
### Examples by Component Type
#### Page Title & Description
```json
{
"proxyHosts": {
"title": "Proxy Hosts",
"description": "Manage your reverse proxy configurations"
}
}
```
#### Form Labels
```json
{
"proxyHosts": {
"domainNames": "Domain Names",
"forwardHost": "Forward Host",
"forwardPort": "Forward Port",
"sslEnabled": "SSL Enabled"
}
}
```
#### Button Actions
```json
{
"proxyHosts": {
"addHost": "Add Proxy Host",
"editHost": "Edit Proxy Host",
"deleteHost": "Delete Proxy Host",
"bulkActions": "Bulk Actions"
}
}
```
#### Table Columns
```json
{
"proxyHosts": {
"columnDomain": "Domain",
"columnTarget": "Target",
"columnStatus": "Status",
"columnActions": "Actions"
}
}
```
#### Confirmation Dialogs
```json
{
"proxyHosts": {
"confirmDelete": "Are you sure you want to delete {{domainName}}?",
"confirmBulkDelete": "Delete {{count}} proxy host(s)?",
"confirmDisable": "Disable this proxy host?"
}
}
```
### Anti-Patterns to Avoid
β **Don't repeat category in key:**
```json
{ "proxyHosts": { "proxyHostsTitle": "..." } } // Wrong
{ "proxyHosts": { "title": "..." } } // Correct
```
β **Don't embed markup:**
```json
{ "common": { "warning": "Warning: ..." } } // Wrong
{ "common": { "warning": "Warning: ..." } } // Correct
```
β **Don't hardcode units:**
```json
{ "uptime": { "responseTime": "Response Time (ms)" } } // Wrong
{ "uptime": { "responseTime": "Response Time", "unitMs": "ms" } } // Correct
```
β **Don't use generic keys for specific content:**
```json
{ "common": { "text1": "...", "text2": "..." } } // Wrong
{ "proxyHosts": { "helpText": "...", "warningText": "..." } } // Correct
```
---
## Risk Assessment & Mitigation
### Risk 1: State Management Re-render Performance
**Risk Level:** π‘ MEDIUM
**Description:** Adding `useTranslation()` hook to every component may cause unnecessary re-renders when language changes, especially in large components like ProxyHosts.tsx (1023 lines).
**Impact:**
- Language changes trigger re-render of all components using `useTranslation()`
- Potential UI lag or frozen state during language switch
- Memory pressure from simultaneous component updates
**Mitigation Strategies:**
1. **Use React.memo for expensive components:**
```tsx
export default React.memo(ProxyHosts)
```
2. **Memoize translation calls in render-heavy components:**
```tsx
const columns = useMemo(() => [
{ header: t('proxyHosts.domain'), ... },
{ header: t('proxyHosts.target'), ... }
], [t, language])
```
3. **Split large components into smaller, memoized subcomponents:**
```tsx
const ProxyHostTable = React.memo(({ data }) => { ... })
const ProxyHostForm = React.memo(({ onSave }) => { ... })
```
4. **Add performance monitoring:**
```tsx
useEffect(() => {
const start = performance.now()
return () => {
const duration = performance.now() - start
if (duration > 100) console.warn('Slow render:', duration)
}
})
```
**Acceptance Criteria:**
- Language switch completes in < 500ms on Desktop
- Language switch completes in < 1000ms on Mobile
- No visible UI freezing during switch
- Memory usage increase < 10% after language switch
---
### Risk 2: Third-Party Component i18n Support
**Risk Level:** π HIGH
**Description:** Some third-party UI components (DataTable, Dialog, DatePicker, etc.) may not properly support dynamic language changes or may have their own i18n systems.
**Affected Components:**
- DataTable (pagination, sorting labels)
- Date/Time Pickers (month names, day names)
- Form validation libraries (error messages)
- Rich text editors
- File upload components
**Mitigation Strategies:**
1. **Audit all third-party components** (Pre-Phase 1):
```bash
grep -r "import.*from" frontend/src/components | grep -E "(table|date|form|picker|editor)"
```
2. **Wrapper pattern for incompatible components:**
```tsx
// Wrap DatePicker with localized props
const LocalizedDatePicker = ({ ...props }) => {
const { i18n } = useTranslation()
return (
)
}
```
3. **Replace components if necessary:**
- Document replacement decisions
- Ensure feature parity
- Test thoroughly
4. **Configure third-party i18n integrations:**
```tsx
// For libraries like react-datepicker
import { registerLocale, setDefaultLocale } from "react-datepicker";
import es from 'date-fns/locale/es';
registerLocale('es', es);
```
**Action Items:**
- Create compatibility matrix (see below)
- Test each component with all 5 languages
- Document workarounds in component README
---
### Risk 3: Date/Time/Number Formatting
**Risk Level:** π‘ MEDIUM
**Description:** Dates, times, numbers, and currencies need locale-aware formatting. Hardcoded formats (MM/DD/YYYY) will not adapt to user locale.
**Examples:**
- Dates: US (12/31/2025) vs EU (31/12/2025)
- Times: 12-hour (3:00 PM) vs 24-hour (15:00)
- Numbers: 1,234.56 (US) vs 1.234,56 (EU)
- Currencies: $1,234.56 vs 1 234,56 β¬
**Mitigation Strategies:**
1. **Use Intl API for formatting:**
```tsx
// Date formatting
const formatDate = (date: Date, locale: string) => {
return new Intl.DateTimeFormat(locale, {
year: 'numeric',
month: 'long',
day: 'numeric'
}).format(date)
}
// Number formatting
const formatNumber = (num: number, locale: string) => {
return new Intl.NumberFormat(locale).format(num)
}
// Currency formatting
const formatCurrency = (amount: number, locale: string, currency: string) => {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency
}).format(amount)
}
```
2. **Create formatting utilities:**
```tsx
// frontend/src/utils/formatting.ts
import { useTranslation } from 'react-i18next'
export const useFormatting = () => {
const { i18n } = useTranslation()
return {
date: (date: Date) => formatDate(date, i18n.language),
time: (date: Date) => formatTime(date, i18n.language),
number: (num: number) => formatNumber(num, i18n.language),
relativeTime: (date: Date) => formatRelativeTime(date, i18n.language)
}
}
```
3. **Use date-fns with locale support:**
```tsx
import { format } from 'date-fns'
import { es, fr, de, zhCN } from 'date-fns/locale'
const locales = { en: enUS, es, fr, de, zh: zhCN }
format(new Date(), 'PPP', { locale: locales[language] })
```
**Acceptance Criteria:**
- All dates use `Intl.DateTimeFormat` or `date-fns` with locale
- All numbers use `Intl.NumberFormat`
- No hardcoded date/number formats in components
---
### Risk 4: RTL (Right-to-Left) Language Support
**Risk Level:** π‘ MEDIUM
**Description:** Future support for RTL languages (Arabic, Hebrew) will require layout and CSS adjustments. Current plan only includes LTR languages, but architecture should not prevent RTL addition.
**Current Languages:** All LTR (English, Spanish, French, German, Chinese)
**Future Consideration:** Arabic (ar), Hebrew (he)
**Mitigation Strategies:**
1. **Use logical CSS properties now:**
```css
/* β Avoid */
margin-left: 16px;
padding-right: 8px;
/* β Use instead */
margin-inline-start: 16px;
padding-inline-end: 8px;
```
2. **Avoid absolute positioning where possible:**
```css
/* β Problematic for RTL */
position: absolute;
left: 0;
/* β Use flexbox/grid */
display: flex;
justify-content: flex-start;
```
3. **Add `dir` attribute support to root:**
```tsx
// main.tsx or App.tsx
useEffect(() => {
document.dir = i18n.dir(i18n.language)
}, [i18n.language])
```
4. **Test with RTL browser extension:**
- Install "Force RTL" browser extension
- Validate layout doesn't break
- Check icon alignment
**Acceptance Criteria:**
- All CSS uses logical properties (inline-start/end)
- No hardcoded left/right positioning
- `dir` attribute infrastructure in place
- Layout tested with "Force RTL" tool
---
### Risk 5: Translation File Drift
**Risk Level:** π HIGH
**Description:** Over time, translation files can become out of sync as developers add keys to English but forget to update other languages, leading to missing translations and fallback to English.
**Impact:**
- Inconsistent user experience across languages
- Some text remains in English in non-English locales
- Hard to track which keys are missing
**Mitigation Strategies:**
1. **Automated sync checking (CI/CD - see Maintenance Strategy section)**
2. **Translation key generation script:**
```bash
# scripts/sync-translations.sh
#!/bin/bash
node scripts/sync-translation-keys.js
```
```javascript
// scripts/sync-translation-keys.js
const fs = require('fs')
const path = require('path')
const localesDir = path.join(__dirname, '../frontend/src/locales')
const enFile = path.join(localesDir, 'en/translation.json')
const enKeys = JSON.parse(fs.readFileSync(enFile, 'utf8'))
const languages = ['es', 'fr', 'de', 'zh']
languages.forEach(lang => {
const langFile = path.join(localesDir, `${lang}/translation.json`)
const langKeys = JSON.parse(fs.readFileSync(langFile, 'utf8'))
const missingKeys = findMissingKeys(enKeys, langKeys)
if (missingKeys.length > 0) {
console.error(`β Missing keys in ${lang}:`, missingKeys)
process.exit(1)
}
})
```
3. **Pull request template requirement:**
- Checklist item: "All translation files updated"
- Automated comment if keys don't match
4. **Fallback chain with warnings:**
```tsx
// i18n.ts
i18n.init({
fallbackLng: 'en',
missingKeyHandler: (lngs, ns, key) => {
console.warn(`Missing translation key: ${key} for language: ${lngs[0]}`)
// Optionally report to error tracking
Sentry.captureMessage(`Missing i18n key: ${key}`)
}
})
```
**Acceptance Criteria:**
- CI fails if translation keys don't match
- Missing keys logged to console in development
- PR template includes translation checklist
---
### Risk Mitigation Summary
| Risk | Level | Primary Mitigation | Monitoring |
|------|-------|-------------------|------------|
| Re-render Performance | π‘ Medium | React.memo, useMemo | Performance profiling in Phase 1 |
| Third-Party Components | π High | Audit + wrapper pattern | Manual QA per component |
| Date/Number Formatting | π‘ Medium | Intl API utilities | Visual QA in all locales |
| RTL Support | π‘ Medium | Logical CSS properties | RTL browser extension testing |
| Translation Drift | π High | CI checks + scripts | Automated on every PR |
---
## Implementation Plan - Revised Phases
**Strategy:** Validate pattern early with high-visibility components, then scale systematically. Each phase includes implementation, testing, code review, and bug fixes.
---
### Phase 1: Layout & Navigation (Days 1-3)
**Objective:** Establish pattern with most visible user-facing component. Validates infrastructure and approach.
**Files:**
- `frontend/src/components/Layout.tsx` (367 lines)
- `frontend/src/components/LanguageSelector.tsx` (already uses translations)
**Tasks:**
- [ ] Day 1: Add missing translation keys (48 new keys) to all 5 language files
- [ ] Day 1: Update navigation array to use `t('navigation.*')` keys
- [ ] Day 1: Update logout/profile buttons
- [ ] Day 1: Update sidebar tooltips
- [ ] Day 2: Create Layout.test.tsx with language switching tests
- [ ] Day 2: Manual QA in all 5 languages
- [ ] Day 2: Code review and address feedback
- [ ] Day 3: Fix bugs, performance profiling, merge PR
**Success Criteria:**
- Navigation menu switches languages instantly
- No console warnings for missing keys
- All 5 languages render correctly
- Performance: < 100ms to switch languages
- Code review approved
**Example Changes:**
```tsx
// Before
const navigation: NavItem[] = [
{ name: 'Dashboard', path: '/', icon: 'π' },
{ name: 'Proxy Hosts', path: '/proxy-hosts', icon: 'π' }
]
// After
const { t } = useTranslation()
const navigation: NavItem[] = [
{ name: t('navigation.dashboard'), path: '/', icon: 'π' },
{ name: t('navigation.proxyHosts'), path: '/proxy-hosts', icon: 'π' }
]
```
---
### Phase 2: ProxyHosts (Days 4-7)
**Objective:** Validate pattern on largest, most complex component. Proves approach scales to complex forms and tables.
**Files:**
- `frontend/src/pages/ProxyHosts.tsx` (1023 lines) **HIGHEST COMPLEXITY**
- `frontend/src/components/ProxyHostForm.tsx` (if exists)
**Tasks:**
- [ ] Day 4: Update PageShell title/description
- [ ] Day 4: Update all button text (Create, Edit, Delete, Bulk Apply)
- [ ] Day 5: Update DataTable column headers
- [ ] Day 5: Update form labels and placeholders
- [ ] Day 5: Update status badges (Enabled/Disabled, SSL indicators)
- [ ] Day 6: Update dialogs (confirmation, bulk update)
- [ ] Day 6: Update toast/notification messages
- [ ] Day 6: Add ProxyHosts.test.tsx
- [ ] Day 6: Manual QA with CRUD operations
- [ ] Day 7: Code review, bug fixes, performance check, merge PR
**Success Criteria:**
- All UI text translates correctly
- Form validation messages localized
- Toast notifications in selected language
- No layout breaks in any language (especially German - longest strings)
- Performance: Page renders in < 200ms after language change
- Code review approved
**Example Changes:**
```tsx
// Before
// After
const { t } = useTranslation()
```
---
### Phase 3: Core Pages (Days 8-12)
**Objective:** Apply validated pattern to remaining core pages. Parallelizable work.
**Files (in priority order):**
1. `SystemSettings.tsx` (430 lines) - Already imports LanguageSelector
2. `Security.tsx` (500 lines)
3. `AccessLists.tsx` (700 lines)
4. `Certificates.tsx` (600 lines)
5. `RemoteServers.tsx` (500 lines)
6. `Domains.tsx` (400 lines)
**Tasks:**
- [ ] Day 8: SystemSettings, Security (2 files)
- [ ] Day 9: AccessLists, Certificates (2 files)
- [ ] Day 10: RemoteServers, Domains (2 files)
- [ ] Day 11: Add tests for all 6 files
- [ ] Day 11: Manual QA for all pages
- [ ] Day 12: Code review, bug fixes, merge PRs
**Success Criteria:**
- All pages follow established pattern
- Tests pass for all components
- No regressions in functionality
- Code reviews approved
---
### Phase 4: Dashboard & Supporting Pages (Days 13-15)
**Objective:** Complete main application pages and validate integration across full workflow.
**Files:**
- `Dashboard.tsx` (177 lines) - **Integration validation**
- `CrowdSecConfig.tsx` (600 lines)
- `WafConfig.tsx` (400 lines)
- `RateLimiting.tsx` (400 lines)
- `Uptime.tsx` (500 lines)
- `Notifications.tsx` (400 lines)
- `UsersPage.tsx` (500 lines)
- `SecurityHeaders.tsx` (800 lines)
**Tasks:**
- [ ] Day 13: Dashboard, CrowdSecConfig, WafConfig
- [ ] Day 14: RateLimiting, Uptime, Notifications, UsersPage
- [ ] Day 14: SecurityHeaders
- [ ] Day 15: Integration tests (full user workflow in each language)
- [ ] Day 15: Code review, bug fixes, merge PRs
**Success Criteria:**
- Dashboard correctly aggregates translated content
- All stats and widgets display localized text
- Full workflow (create proxy β configure SSL β test) works in all languages
- Code reviews approved
---
### Phase 5: Auth & Setup Pages (Days 16-17)
**Objective:** Critical user onboarding experience. Must be perfect.
**Files:**
- `Login.tsx` (200 lines)
- `Setup.tsx` (300 lines)
- `Account.tsx` (300 lines)
**Tasks:**
- [ ] Day 16: Login, Setup pages
- [ ] Day 16: Account page
- [ ] Day 16: Test authentication flows in all languages
- [ ] Day 17: QA first-time setup experience
- [ ] Day 17: Code review, bug fixes, merge PR
**Success Criteria:**
- First-time users see setup in their browser's default language
- Login errors display in correct language
- Form validation messages localized
- Success/error toasts localized
- Code review approved
---
### Phase 6: Utility Pages & Final Integration (Days 18-19)
**Objective:** Complete remaining pages and ensure consistency.
**Files:**
- `Backups.tsx` (400 lines)
- `Tasks.tsx` (300 lines)
- `Logs.tsx` (400 lines)
- `ImportCaddy.tsx` (200 lines)
- `ImportCrowdSec.tsx` (200 lines)
- `SMTPSettings.tsx` (400 lines)
**Tasks:**
- [ ] Day 18: All utility pages
- [ ] Day 18: Import pages
- [ ] Day 18: SMTP settings
- [ ] Day 19: Final integration QA
- [ ] Day 19: Code reviews, bug fixes, merge PRs
**Success Criteria:**
- All pages translated
- Import workflows work in all languages
- No missing translation keys
- Code reviews approved
---
### Phase 7: Comprehensive QA & Polish (Days 20-23)
**Objective:** Thorough testing, bug fixes, performance optimization, and production readiness.
**Tasks:**
#### Day 20: Automated Testing
- [ ] Run full test suite in all 5 languages
- [ ] Translation coverage tests (100% key coverage)
- [ ] Bundle size analysis (ensure no significant increase)
- [ ] Performance profiling (language switching speed)
- [ ] Accessibility testing (screen reader compatibility)
#### Day 21: Manual QA - Core Workflows
- [ ] Test full user workflows in all 5 languages:
- [ ] First-time setup
- [ ] Login/logout
- [ ] Create/edit/delete proxy host
- [ ] Configure SSL certificate
- [ ] Apply access list
- [ ] Configure security settings
- [ ] View logs and tasks
- [ ] Test language switching mid-workflow (e.g., while editing form)
- [ ] Test WebSocket reconnection with language changes (logs page)
- [ ] Test browser back/forward with language changes
#### Day 22: Edge Cases & Error Handling
- [ ] Backend API errors in all languages
- [ ] Network errors with WebSocket (logs page)
- [ ] Mid-edit language switches (forms preserve data)
- [ ] Rapid language switching (no race conditions)
- [ ] Browser locale detection on first visit
- [ ] LocalStorage corruption/missing (graceful fallback)
#### Day 23: Final Polish & Documentation
- [ ] Fix all bugs found in QA
- [ ] Update user documentation with language switching instructions
- [ ] Create developer guide for adding new translations
- [ ] Final performance check
- [ ] Prepare release notes
**Success Criteria:**
- All automated tests pass
- All manual QA workflows complete successfully
- No P0/P1 bugs remaining
- Performance meets targets (< 500ms language switch)
- Bundle size increase < 50KB
- Documentation updated
---
## Detailed Timeline (3-4 Weeks)
### Week 1: Foundation & Validation
| Day | Phase | Tasks | Deliverables |
|-----|-------|-------|--------------|
| **Mon 1** | Phase 1 | Add missing keys, update Layout.tsx navigation | Navigation menu translations |
| **Tue 2** | Phase 1 | Tests, QA, code review | Layout PR ready |
| **Wed 3** | Phase 1 | Bug fixes, performance, merge | β Layout complete |
| **Thu 4-5** | Phase 2 | ProxyHosts.tsx implementation | ProxyHosts translations |
| **Fri 5** | Phase 2 | ProxyHosts forms, tables | ProxyHosts UI complete |
**Week 1 Milestones:**
- β Navigation fully translated (most visible change)
- β ProxyHosts 80% complete (validates complex component approach)
- β Pattern established and documented
---
### Week 2: Core Pages Rollout
| Day | Phase | Tasks | Deliverables |
|-----|-------|-------|--------------|
| **Mon 6-7** | Phase 2 | ProxyHosts dialogs, toasts, tests, QA | β ProxyHosts complete |
| **Tue 8** | Phase 3 | SystemSettings, Security | 2 pages complete |
| **Wed 9** | Phase 3 | AccessLists, Certificates | 2 pages complete |
| **Thu 10** | Phase 3 | RemoteServers, Domains | 2 pages complete |
| **Fri 11-12** | Phase 3 | Tests, QA, code reviews, bug fixes | β 6 core pages complete |
**Week 2 Milestones:**
- β ProxyHosts complete (largest component done)
- β 6 additional core pages translated
- β All security-related pages functional
---
### Week 3: Dashboard Integration & Auth
| Day | Phase | Tasks | Deliverables |
|-----|-------|-------|--------------|
| **Mon 13** | Phase 4 | Dashboard, CrowdSec, WAF | Dashboard + 2 config pages |
| **Tue 14** | Phase 4 | Rate Limiting, Uptime, Notifications, Users, Headers | 5 pages complete |
| **Wed 15** | Phase 4 | Integration tests, QA, bug fixes | β All main pages complete |
| **Thu 16** | Phase 5 | Login, Setup, Account | Auth flow complete |
| **Fri 17** | Phase 5 | Auth QA, bug fixes | β Critical auth complete |
**Week 3 Milestones:**
- β Dashboard integrated (validates cross-page consistency)
- β All security and monitoring pages complete
- β Auth and setup flows fully translated
---
### Week 4: Finalization & QA
| Day | Phase | Tasks | Deliverables |
|-----|-------|-------|--------------|
| **Mon 18** | Phase 6 | Backups, Tasks, Logs, Import pages, SMTP | All utility pages |
| **Tue 19** | Phase 6 | Final integration, code reviews | β All pages complete |
| **Wed 20** | Phase 7 | Automated testing, bundle analysis | Test results, metrics |
| **Thu 21** | Phase 7 | Manual QA - core workflows | QA report |
| **Fri 22** | Phase 7 | Edge case testing, bug fixes | Bug list, fixes |
| **Mon 23** | Phase 7 | Final polish, documentation | β Production ready |
**Week 4 Milestones:**
- β 100% of pages translated
- β All automated tests passing
- β All manual QA complete
- β Documentation updated
- β Ready for production deployment
---
### Buffer Time (Optional Week 5)
**Purpose:** Handle unexpected delays, additional bugs, or extended QA
| Day | Tasks |
|-----|-------|
| Mon 24 | Address any remaining P1 bugs |
| Tue 25 | Additional QA if needed |
| Wed 26 | Performance optimization |
| Thu 27 | Stakeholder review |
| Fri 28 | Final production prep |
---
### Daily Stand-up Template
**What was completed yesterday:**
- [Specific pages/components translated]
- [Tests added]
- [Bugs fixed]
**What will be done today:**
- [Specific pages to translate]
- [Tests to add]
- [Code reviews to complete]
**Blockers:**
- [Any issues blocking progress]
- [Missing information or dependencies]
**QA Status:**
- [Pages ready for QA]
- [Bugs found]
- [Bugs fixed]
---
## Code Review Checklist
Use this checklist for EVERY pull request containing translation changes.
### Pre-Review (Author Self-Check)
- [ ] All hardcoded strings replaced with translation keys
- [ ] Translation keys added to ALL 5 language files (en, es, fr, de, zh)
- [ ] Keys follow naming convention (category.subcategory.descriptor)
- [ ] Dynamic content uses interpolation (`{{variableName}}`)
- [ ] Pluralization handled correctly (count, count_plural)
- [ ] Component imports `useTranslation` from 'react-i18next'
- [ ] Component calls `const { t } = useTranslation()` inside function body
- [ ] Tests added/updated for component
- [ ] Manual QA completed in at least 3 languages
- [ ] No console warnings for missing keys
- [ ] No layout breaks or text overflow in any language
### Code Quality
- [ ] **Import statement correct:**
```tsx
import { useTranslation } from 'react-i18next'
```
- [ ] **Hook placement correct (inside component):**
```tsx
export default function MyComponent() {
const { t } = useTranslation() // β Correct
// ...
}
```
- [ ] **Translation keys valid (no typos, exist in files):**
```tsx
t('proxyHosts.title') // β Key exists
t('proxyhosts.titel') // β Typo, wrong key
```
- [ ] **Interpolation syntax correct:**
```tsx
t('dashboard.activeHosts', { count: 5 }) // β Correct
t('dashboard.activeHosts', { num: 5 }) // β Variable name mismatch
```
- [ ] **No string concatenation:**
```tsx
// β Wrong
{t('common.total')}: {count}
// β Correct
{t('common.totalCount', { count })}
```
### Translation File Quality
- [ ] **All 5 files updated (en, es, fr, de, zh)**
- [ ] **Keys in same order in all files**
- [ ] **No duplicate keys**
- [ ] **No missing commas or JSON syntax errors**
- [ ] **Interpolation placeholders match:**
```json
// en
"activeHosts": "{{count}} active"
// es (same placeholder name)
"activeHosts": "{{count}} activos"
```
- [ ] **Pluralization implemented if needed:**
```json
"count": "{{count}} item",
"count_plural": "{{count}} items"
```
### Performance
- [ ] **Large components use React.memo:**
```tsx
export default React.memo(ProxyHosts)
```
- [ ] **Expensive translation calls memoized:**
```tsx
const columns = useMemo(() => [
{ header: t('common.name'), ... }
], [t])
```
- [ ] **No unnecessary re-renders on language change**
- [ ] **Bundle size increase documented (if > 5KB)**
### Testing
- [ ] **Unit tests added/updated:**
```tsx
it('renders in Spanish', () => {
i18n.changeLanguage('es')
render()
expect(screen.getByText('Panel de Control')).toBeInTheDocument()
})
```
- [ ] **Translation key existence test:**
```tsx
it('all keys exist in all languages', () => {
const enKeys = Object.keys(en)
languages.forEach(lang => {
expect(Object.keys(translations[lang])).toEqual(enKeys)
})
})
```
- [ ] **Language switching test:**
```tsx
it('updates when language changes', () => {
const { rerender } = render()
expect(screen.getByText('Dashboard')).toBeInTheDocument()
i18n.changeLanguage('es')
rerender()
expect(screen.getByText('Panel de Control')).toBeInTheDocument()
})
```
### Accessibility
- [ ] **ARIA labels translated:**
```tsx
```
- [ ] **Form labels associated correctly:**
```tsx
```
- [ ] **Error messages accessible:**
```tsx
{t('errors.required')}
```
- [ ] **Screen reader tested (if available)**
### UI/UX
- [ ] **No text overflow in any language (especially German)**
- [ ] **Buttons and labels don't break layout**
- [ ] **Proper spacing maintained**
- [ ] **Text direction correct (all LTR for current languages)**
- [ ] **Font rendering acceptable for all languages**
### Edge Cases
- [ ] **Empty states translated:**
```tsx
{items.length === 0 &&