9.3 KiB
L10n Cleanup + Stable Error Code + Frontend Text Migration Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Remove redundant l10n wrappers, introduce backend stable/mappable error codes for HTTP contracts, and continue frontend hardcoded-text localization migration to zh/en with default zh.
Architecture: Keep Flutter UI localization in lib/l10n as single source of truth, minimize cross-layer localization coupling, and use backend RFC7807 + code/params as machine-readable contract. Frontend maps code -> l10n key for user-facing messages while preserving fallback behavior.
Tech Stack: Flutter gen-l10n, FastAPI (RFC7807), Pydantic models, Dio client error mapping, existing AGENTS/rules constraints.
Task 1: Freeze and baseline current behavior
Files:
- Modify: none (read-only task)
- Verify:
apps/lib/**,backend/src/**,docs/protocols/**
Step 1: Snapshot app localization status
Run: python scripts/count_cn_literals.py (or equivalent one-off command)
Expected: baseline count and top files with Chinese literals.
Step 2: Snapshot backend detail-string usage
Run: python scripts/count_http_detail_usage.py (or equivalent one-off command)
Expected: per-file count of HTTPException(detail=...) hotspots.
Step 3: Capture baseline checks
Run: cd apps && flutter analyze
Expected: no new errors, only known existing warnings/infos.
Run: cd backend && uv run pytest -q (or targeted fast suite if full too slow)
Expected: baseline pass/fail recorded for regression comparison.
Task 2: Refactor l10n structure to remove redundant wrapper responsibilities
Files:
- Modify:
apps/lib/app/app.dart - Modify: UI files currently importing
apps/lib/core/l10n/l10n.dart - Delete/Modify:
apps/lib/core/l10n/l10n.dart(depending on final outcome) - Verify: generated files under
apps/lib/l10n/
Step 1: Define target rule
Rule:
- UI layer uses
context.l10n. - Non-UI layer does not depend on ad-hoc global locale state.
- If non-UI needs localization, pass already-localized strings in from caller or inject mapper service.
Step 2: Write failing/static guard checks
Add temporary grep checks:
- Fail when new code adds
L10n.currentin feature/presentation. - Fail when
core/l10n/l10n.dartis reintroduced for convenience access.
Step 3: Replace call sites incrementally
For each file:
- Replace
L10n.current.xxxwithcontext.l10n.xxxwhereBuildContextexists. - For cubit/service/form validators, inject message providers or pass messages from UI.
- Keep behavior unchanged.
Step 4: Remove locale global mutation path
In app.dart:
- Remove
L10n.setLocale(...)style side effects. - Keep Flutter-native delegates +
supportedLocales+ default locale logic.
Step 5: Delete redundant wrapper (if no remaining valid use case)
Delete apps/lib/core/l10n/l10n.dart only after all references are removed and non-UI strategy is in place.
Step 6: Verify
Run: cd apps && flutter gen-l10n && flutter analyze
Expected: no errors.
Task 3: Define backend stable error code contract (RFC7807 extension)
Files:
- Modify:
backend/src/core/http/response.py - Modify:
backend/src/app.py - Create:
backend/src/core/http/errors.py - Modify:
docs/protocols/agent/api-endpoints.md - (optional) Create:
docs/protocols/common/error-contract.md
Step 1: Extend problem details schema
Add fields:
code: str | Noneparams: dict[str, str | int | float | bool] | None
Preserve RFC7807 required fields and media type.
Step 2: Introduce unified domain error type
In core/http/errors.py, create exception class carrying:
- http status
- stable error code (UPPER_SNAKE_CASE)
- optional params
- optional internal detail
Step 3: Wire global exception handlers
In app.py:
- Convert domain exceptions to problem+json with
codeandparams. - Keep fallback for unknown exceptions.
Step 4: Define code naming convention
Examples:
AUTH_INVALID_TOKENAUTH_TOKEN_EXPIREDSCHEDULE_ITEM_NOT_FOUNDTODO_TITLE_REQUIREDFRIENDSHIP_ALREADY_EXISTS
Task 4: Migrate backend hotspots from free-text detail to stable codes
Files:
- Modify:
backend/src/v1/friendships/service.py - Modify:
backend/src/v1/schedule_items/service.py - Modify:
backend/src/v1/todo/service.py - Modify:
backend/src/v1/agent/service.py - Modify:
backend/src/v1/users/service.py - Modify:
backend/src/v1/memories/service.py - Modify:
backend/src/v1/auth/gateway.py - Modify:
backend/src/v1/agent/router.py - Modify: other files with
HTTPException(detail=...)
Step 1: Prioritize by impact
Order:
- Auth
- Agent
- Todo/Schedule/Friendships
- Users/Memories
Step 2: Replace throw sites
For each detail-based throw:
- Map to stable
code. - Keep detail only as optional server diagnostic text.
- Add params when useful (e.g., max size, field, limit).
Step 3: Preserve backwards compatibility window
During transition:
- Keep
detailpresent. - Add
code/paramsimmediately. - Frontend prefers
code, falls back to existing behavior.
Task 5: Frontend network error mapping to l10n via backend code
Files:
- Modify:
apps/lib/core/network/api_exception.dart - Create:
apps/lib/core/network/error_code_mapper.dart - Modify: call sites currently displaying raw backend detail
- Modify:
apps/lib/l10n/app_zh.arb,apps/lib/l10n/app_en.arb
Step 1: Parse code and params from response payload
In ApiException.fromDioError:
- Read RFC7807 + extension fields.
- Keep
statusCodefallback behavior.
Step 2: Map code -> localized message
Implement central mapper:
- Input: code/status/params
- Output: localized user-facing string key resolution
Step 3: Fallback strategy
Priority:
- known code mapping
- status-based generic mapping
- safe generic fallback (
request failedlocalized)
Step 4: Replace UI direct usage of raw server detail
Audit and update places where e.toString() or backend detail is shown directly.
Task 6: Continue frontend hardcoded text migration (remaining files)
Files:
- Modify:
apps/lib/features/settings/presentation/screens/*.dart(remaining high-count files) - Modify:
apps/lib/features/calendar/presentation/screens/*.dart - Modify:
apps/lib/features/calendar/presentation/widgets/*.dart - Modify:
apps/lib/l10n/app_zh.arb,apps/lib/l10n/app_en.arb
Step 1: Batch by screen group
Batch A: settings deep pages Batch B: calendar pages Batch C: shared/home leftovers
Step 2: Migrate with key hygiene
Rules:
- key names are feature-prefixed and stable
- dynamic texts use placeholders, not string concatenation
- avoid duplicate semantic keys
Step 3: After each batch, run verification
Run:
cd apps && flutter gen-l10ncd apps && flutter analyze
Track remaining hardcoded-literal count after each batch.
Task 7: Protocol docs and test updates
Files:
- Modify:
docs/protocols/agent/api-endpoints.md - Modify/Create:
docs/protocols/common/error-contract.md - Modify: backend integration/unit tests asserting only
detail - Modify: frontend tests around error display/mapping
Step 1: Document new error response shape
Example:
{
"type": "about:blank",
"title": "Unprocessable Entity",
"status": 422,
"detail": "Validation failed",
"code": "TODO_TITLE_REQUIRED",
"params": {"field": "title"},
"instance": "/api/v1/todo"
}
Step 2: Update tests to assert codes first
Replace brittle text assertions with:
statuscode- optional
params
Task 8: Final verification gate
Files:
- Verify only
Step 1: Apps verification
Run:
cd apps && flutter gen-l10ncd apps && flutter analyze
Step 2: Backend verification
Run:
cd backend && uv run ruff check .cd backend && uv run basedpyrightcd backend && uv run pytest -q
Step 3: Cross-contract smoke
Run targeted API checks ensuring error payload includes code for representative modules.
Task 9: Rollout and compatibility
Files:
- Modify: release notes/changelog if used
Step 1: Progressive rollout strategy
- Phase 1: backend emits both
detail+code - Phase 2: frontend consumes
codewith fallback - Phase 3: clean up legacy detail-dependent branches
Step 2: Monitoring
- Log unknown/unmapped error codes on frontend
- Add backend metrics for top emitted error codes
Risks and mitigations
- Risk: non-UI code loses localization access after wrapper removal
- Mitigation: inject messages from UI/service boundary; avoid static locale globals.
- Risk: backend code migration is broad (many detail throws)
- Mitigation: staged module-by-module migration + compatibility window.
- Risk: front/back mismatch in error code enum
- Mitigation: shared protocol doc + CI checks for known code list.
Done criteria
apps/lib/core/l10n/l10n.dartremoved or reduced to zero-overlap minimal utility with explicit justification.- Backend RFC7807 responses include stable
code(and optionalparams) on migrated endpoints. - Frontend maps known codes to zh/en l10n; raw detail is no longer primary user-facing string.
- Hardcoded visible Chinese text count in
apps/libreduced to agreed threshold or zero for targeted modules. - Docs and tests updated accordingly.