131 lines
3 KiB
Markdown
131 lines
3 KiB
Markdown
# TT-011 — Localisation (i18n)
|
|
|
|
**Type:** Story
|
|
**Priority:** Medium
|
|
**Labels:** i18n, l10n, infrastructure
|
|
**Depends on:** TT-001
|
|
**Blocks:** TT-006, TT-007, TT-008, TT-009, TT-010
|
|
|
|
---
|
|
|
|
## Summary
|
|
Set up `flutter_localizations` with ARB files for English (`en`) and German
|
|
(`de`). All UI strings must be externalised — no hardcoded display text in
|
|
widget files.
|
|
|
|
## Setup
|
|
|
|
### l10n.yaml (project root)
|
|
```yaml
|
|
arb-dir: lib/core/l10n
|
|
template-arb-file: app_en.arb
|
|
output-localization-file: app_localizations.dart
|
|
output-class: AppLocalizations
|
|
```
|
|
|
|
### File structure
|
|
```
|
|
lib/core/l10n/
|
|
app_en.arb ← template (English)
|
|
app_de.arb ← German translations
|
|
```
|
|
|
|
Generated: `lib/core/l10n/app_localizations.dart` (do not edit manually)
|
|
|
|
### Usage in widgets
|
|
```dart
|
|
import 'package:timetrack/core/l10n/app_localizations.dart';
|
|
// ...
|
|
Text(AppLocalizations.of(context)!.timerStart)
|
|
```
|
|
|
|
## Strings to externalise (minimum set)
|
|
|
|
### Navigation
|
|
```json
|
|
"navTimer": "Timer",
|
|
"navEntries": "Entries",
|
|
"navProjects": "Projects",
|
|
"navReports": "Reports",
|
|
"navSettings": "Settings"
|
|
```
|
|
|
|
### Timer
|
|
```json
|
|
"timerStart": "Start",
|
|
"timerStop": "Stop",
|
|
"timerDiscard": "Discard",
|
|
"timerDiscardConfirm": "Discard this entry?",
|
|
"timerSelectProject": "Select project",
|
|
"timerAddNote": "Add a note…",
|
|
"timerTodayTotal": "Today: {duration}"
|
|
```
|
|
|
|
### Entries
|
|
```json
|
|
"entriesTitle": "Entries",
|
|
"entriesEmpty": "No entries yet",
|
|
"entriesAdd": "Add entry",
|
|
"entriesDeleteUndo": "Entry deleted",
|
|
"entriesUndo": "Undo"
|
|
```
|
|
|
|
### Projects
|
|
```json
|
|
"projectsTitle": "Projects",
|
|
"projectsEmpty": "No projects yet",
|
|
"projectsAdd": "Add project",
|
|
"projectsActive": "Active",
|
|
"projectsArchived": "Archived",
|
|
"projectsName": "Name",
|
|
"projectsDescription": "Description",
|
|
"projectsArchive": "Archive",
|
|
"projectsDeleteBlocked": "Cannot delete — project has entries"
|
|
```
|
|
|
|
### Reports
|
|
```json
|
|
"reportsTitle": "Reports",
|
|
"reportsDay": "Day",
|
|
"reportsWeek": "Week",
|
|
"reportsMonth": "Month",
|
|
"reportsTotal": "Total",
|
|
"reportsNoData": "No data for this period"
|
|
```
|
|
|
|
### Settings / Export
|
|
```json
|
|
"settingsTitle": "Settings",
|
|
"settingsTheme": "Theme",
|
|
"settingsThemeSystem": "System",
|
|
"settingsThemeLight": "Light",
|
|
"settingsThemeDark": "Dark",
|
|
"settingsLanguage": "Language",
|
|
"settingsExport": "Export data",
|
|
"exportFormat": "Format",
|
|
"exportRange": "Date range",
|
|
"exportShare": "Share"
|
|
```
|
|
|
|
### Common
|
|
```json
|
|
"cancel": "Cancel",
|
|
"save": "Save",
|
|
"delete": "Delete",
|
|
"edit": "Edit",
|
|
"confirm": "Confirm"
|
|
```
|
|
|
|
## Acceptance Criteria
|
|
- [ ] `l10n.yaml` present at project root
|
|
- [ ] `app_en.arb` contains all strings listed above
|
|
- [ ] `app_de.arb` contains all German translations (no English fallback strings)
|
|
- [ ] `flutter gen-l10n` (or `flutter pub get`) generates `app_localizations.dart`
|
|
- [ ] Zero hardcoded display strings in any `presentation/` file
|
|
- [ ] Switching language in Settings updates all visible strings immediately
|
|
- [ ] Widget test: locale override renders German strings
|
|
|
|
## Files to create
|
|
- `l10n.yaml`
|
|
- `lib/core/l10n/app_en.arb`
|
|
- `lib/core/l10n/app_de.arb`
|