Files
DriverVault/Phone App/assets/i18n/en.json
T
tajniak81andClaude Opus 4.8 b6bb6b1df0 Add a language-switch system with per-language files
Introduce a hand-rolled i18n layer across all three UIs, each reading its
text from per-language JSON files (English base + Polish + Danish). Nothing
in the converted screens hardcodes English any more.

- Web App (Vue): src/i18n/{en,pl,da}.json + index.js exposing t()/tSplit(),
  reactive to the signed-in profile locale. Every view, component, form and
  the status labels in lib/format.js go through t().
- API Server panel (Vue): src/i18n/ with its own localStorage-persisted
  language (the panel has no user profile) and a header language picker.
  Chrome, cards, login and API section titles translated; endpoint reference
  descriptions intentionally kept in English. Rebuilt embedded dist.
- Phone App (Flutter): assets/i18n/ + lib/i18n.dart loaded at startup,
  driven by AppSettings.locale. Nav, login, lock, dashboard, the full
  Settings panel (incl. language picker) and format.dart status labels
  translated; remaining detail screens fall back to English.

Language = the language half of the existing BCP-47 locale; the region half
still drives date/number/currency formatting. Missing keys fall back to
English, and plurals use Intl.PluralRules / Intl.plural so Polish gets the
correct one/few/many forms. Settings flags languages without a translation.

Tests updated to assert the localized (Polish) status wording; all pass.
See TRANSLATIONS.md for the format and how to add a language.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 20:07:48 +02:00

205 lines
6.9 KiB
JSON

{
"common": {
"save": "Save",
"saving": "Saving…",
"saved": "Saved ✓",
"cancel": "Cancel",
"remove": "Remove",
"retry": "Retry",
"required": "Required",
"confirm": "Confirm",
"empty": "—"
},
"nav": {
"garage": "Garage",
"settings": "Settings",
"users": "Users"
},
"login": {
"tagline": "Your car, on track.",
"email": "Email",
"password": "Password",
"showPassword": "Show password",
"hidePassword": "Hide password",
"submit": "Sign in",
"submitting": "Signing in…",
"or": "or",
"signInWithFace": "Sign in with face recognition",
"signInWithFingerprint": "Sign in with fingerprint",
"signInWithBiometrics": "Sign in with biometrics",
"enrollTitle": "Enable biometric sign-in?",
"enrollBody": "Next time you can sign in with {method} instead of typing your password.",
"enrollNotNow": "Not now",
"enrollEnable": "Enable",
"methodFace": "face recognition",
"methodFingerprint": "your fingerprint",
"methodBiometrics": "biometrics",
"bioReasonSignInAs": "Sign in as {email}",
"bioReasonSignIn": "Sign in to DriverVault",
"savedInvalid": "Saved sign-in is no longer valid. Please sign in with your password.",
"serverSettings": "Server settings",
"apiServerUrl": "API server URL",
"leaveBlank": "Leave blank to use the default.",
"reset": "Reset",
"savedNote": "Saved ✓",
"resetNote": "Reset ✓"
},
"lock": {
"title": "DriverVault is locked",
"reason": "Unlock DriverVault",
"unlock": "Unlock",
"unlocking": "Unlocking…",
"usePassword": "Use password instead"
},
"dashboard": {
"eyebrow": "YOUR CARS",
"title": "Garage",
"addCar": "Add car",
"lightMode": "Light mode",
"darkMode": "Dark mode",
"logOut": "Log out",
"empty": "No cars yet.",
"shared": "Shared",
"sharedReadOnly": "Shared · read-only",
"serviceLife": "SERVICE LIFE",
"lastService": "Last service",
"currentOdometer": "Current odometer",
"nextDue": "Next due",
"nextDueKm": "Next due km",
"serviceRecords": {
"one": "{n} service record",
"other": "{n} service records"
}
},
"settings": {
"title": "Settings",
"account": {
"title": "Account",
"name": "Name",
"nameSaved": "Name saved.",
"email": "Email",
"verified": "Verified",
"notVerified": "Not verified",
"sending": "Sending…",
"resendVerification": "Resend verification email",
"verificationRequested": "Verification email requested.",
"changePassword": "Change password",
"currentPassword": "Current password",
"newPassword": "New password (min 8)",
"confirmNewPassword": "Confirm new password",
"tooShort": "New password must be at least 8 characters.",
"mismatch": "New password and confirmation don't match.",
"passwordUpdated": "Password updated.",
"updating": "Updating…",
"updatePassword": "Update password"
},
"appearance": {
"title": "Appearance",
"theme": "Theme",
"themeLight": "Light",
"themeDark": "Dark",
"themeSystem": "System",
"language": "Language",
"languageHint": "App text, and the names of months and days.",
"languageFallbackHint": "This language isn't translated yet — the app text stays in English.",
"region": "Region",
"regionHint": "Number and currency layout.",
"currency": "Currency",
"currencyHint": "Example: {example}. Amounts are display-only — nothing is converted.",
"dateFormat": "Date format",
"dateHint": "Example: {example}",
"fontSize": "Font size",
"fontSmall": "Small",
"fontMedium": "Medium",
"fontLarge": "Large"
},
"profile": {
"title": "Profile",
"working": "Working…",
"uploadPhoto": "Upload photo",
"remove": "Remove",
"bio": "Bio",
"bioHint": "A short note visible to other people in your household.",
"bioSaved": "Bio saved.",
"saveBio": "Save bio"
},
"security": {
"title": "Security",
"checkingDevice": "Checking device…",
"biometricSignIn": "Biometric sign-in",
"biometricAvailable": "Sign in with {method} instead of your password.",
"biometricUnavailable": "No biometrics are enrolled on this device.",
"methodFaceOrFingerprint": "face or fingerprint",
"methodFace": "face recognition",
"methodFingerprint": "fingerprint",
"methodBiometrics": "biometrics",
"turnedOff": "Biometric sign-in turned off",
"enabled": "Biometric sign-in enabled",
"couldNotEnable": "Could not enable: {error}",
"confirmPassword": "Confirm your password",
"password": "Password"
},
"privacy": {
"title": "Privacy & security",
"body": "Two-factor authentication isn't available yet. Sessions are held as server-issued tokens that expire on their own, so signing out ends this device's session only. To lock out every device, change your password above.",
"signOut": "Sign out"
},
"danger": {
"title": "Danger zone",
"body": "Deleting your account removes your login and profile. It does not delete your household's shared cars or service history. There's a 3-day cooldown before deletion is final, and you can cancel any time before then.",
"deleteAccount": "Delete my account",
"typeToConfirm": "Type {email} to confirm",
"typeEmailPrompt": "Type your email to confirm.",
"requesting": "Requesting…",
"requestDeletion": "Request deletion",
"requestedOn": "Account deletion requested on {date}. {tail}",
"cooldownPassed": "The cooldown has passed. You can now finalize the deletion.",
"canStillCancel": "You can still cancel — it becomes permanent after the 3-day cooldown.",
"cancelRequest": "Cancel deletion request",
"permanentlyDelete": "Permanently delete",
"finalizeTitle": "Delete account?",
"finalizeBody": "This permanently deletes your account. This cannot be undone.",
"delete": "Delete"
}
},
"status": {
"noData": "No data",
"serviceOverdueDays": "Service Overdue {days}d",
"dueInDays": "Due in {days}d",
"okDays": "OK · {days}d",
"noKm": "No km",
"serviceOverdueKm": "Service Overdue {km} km",
"inKm": "In {km} km",
"kmLeft": "{km} km left",
"expiredAgo": "Expired {days}d ago",
"expiresToday": "Expires today",
"renewInDays": "Renew in {days}d",
"validDays": "Valid · {days}d",
"noExpiry": "No expiry",
"done": "Done",
"noTrigger": "No trigger",
"overdue": "Overdue",
"overdueBy": "Overdue {parts}",
"dueIn": "Due in {parts}",
"upcoming": "Upcoming",
"today": "today",
"days": "{days}d",
"km": "{km} km",
"warrantyExpiredAgo": "Warranty expired {days}d ago",
"warrantyEndsIn": "Warranty ends in {days}d",
"underWarranty": "Under warranty · {days}d"
}
}