From 99179df9e2ebd9c90bbacd0639966d4fbca814f2 Mon Sep 17 00:00:00 2001 From: Niraj Yadav Date: Sat, 8 Aug 2026 15:03:35 +0530 Subject: [PATCH 1/9] fix(validation): respect configured date formats Validate localized form dates strictly while keeping API dates ISO-safe. Signed-off-by: Niraj Yadav --- src/__tests__/date-validation.test.ts | 67 +++++++++++++++++++++++++++ src/lib/domain/compliance.ts | 31 ++++++++++++- src/lib/domain/fuel.ts | 5 +- src/lib/domain/maintenance.ts | 5 +- src/lib/domain/reminder.ts | 13 +++++- src/lib/domain/shared.ts | 22 +++++++-- 6 files changed, 135 insertions(+), 8 deletions(-) create mode 100644 src/__tests__/date-validation.test.ts diff --git a/src/__tests__/date-validation.test.ts b/src/__tests__/date-validation.test.ts new file mode 100644 index 00000000..546bc09c --- /dev/null +++ b/src/__tests__/date-validation.test.ts @@ -0,0 +1,67 @@ +import { describe, expect, it } from 'vitest'; +import { apiDateString, dateStringForFormat } from '$lib/domain/shared'; +import { maintenanceFormSchema } from '$lib/domain/maintenance'; +import { complianceFormSchema } from '$lib/domain/compliance'; + +describe('localized date validation', () => { + it('accepts days greater than 12 in day-first formats', () => { + expect(dateStringForFormat('dd/MM/yyyy').safeParse('13/08/2026').success).toBe(true); + expect(dateStringForFormat('dd/MM/yyyy').safeParse('31/12/2026').success).toBe(true); + }); + + it('validates against the configured field order', () => { + expect(dateStringForFormat('MM/dd/yyyy').safeParse('08/13/2026').success).toBe(true); + expect(dateStringForFormat('MM/dd/yyyy').safeParse('13/08/2026').success).toBe(false); + }); + + it('rejects impossible and partially matching dates', () => { + const schema = dateStringForFormat('dd/MM/yyyy'); + expect(schema.safeParse('31/02/2026').success).toBe(false); + expect(schema.safeParse('13/08/2026 trailing').success).toBe(false); + expect(schema.safeParse('').success).toBe(false); + }); + + it('rejects calendar dates that JavaScript would silently normalize', () => { + expect(apiDateString.safeParse('2026-02-31').success).toBe(false); + expect(apiDateString.safeParse('2026-08-13T12:00:00.000Z').success).toBe(true); + }); + + it('uses localized validation in the maintenance form schema', () => { + const result = maintenanceFormSchema('dd/MM/yyyy').safeParse({ + id: null, + vehicleId: '123e4567-e89b-42d3-a456-426614174000', + date: '13/08/2026', + odometer: 1, + serviceCenter: 'Garage', + cost: 0, + notes: null, + attachment: null + }); + + expect(result.success).toBe(true); + }); + + it('compares localized compliance dates chronologically', () => { + const base = { + id: null, + vehicleId: '123e4567-e89b-42d3-a456-426614174000', + type: 'insurance' as const, + otherLabel: null, + documentNumber: 'ABC123', + issuer: 'Insurer', + startDate: '13/08/2026', + recurrenceType: 'none' as const, + recurrenceInterval: 1, + cost: null, + notes: null, + attachment: null + }; + + expect( + complianceFormSchema('dd/MM/yyyy').safeParse({ ...base, endDate: '14/08/2026' }).success + ).toBe(true); + expect( + complianceFormSchema('dd/MM/yyyy').safeParse({ ...base, endDate: '12/08/2026' }).success + ).toBe(false); + }); +}); diff --git a/src/lib/domain/compliance.ts b/src/lib/domain/compliance.ts index 8492746b..71f1d14c 100644 --- a/src/lib/domain/compliance.ts +++ b/src/lib/domain/compliance.ts @@ -5,7 +5,13 @@ import Leaf from '@lucide/svelte/icons/leaf'; import ClipboardCheck from '@lucide/svelte/icons/clipboard-check'; import FileText from '@lucide/svelte/icons/file-text'; import Shapes from '@lucide/svelte/icons/shapes'; -import { apiDateString, optionalApiDateString } from './shared'; +import { + apiDateString, + dateStringForFormat, + optionalApiDateString, + optionalDateStringForFormat +} from './shared'; +import { parseWithFormat } from '$lib/helper/date.helper'; import { getNextDueDate } from '$lib/helper/recurrence.helper'; /** @@ -196,9 +202,30 @@ export const complianceSchema = z if (data.endDate === undefined) return true; if (!data.endDate) return false; if (!data.startDate) return true; - return new Date(data.endDate) > new Date(data.startDate); + const startDate = new Date(data.startDate); + const endDate = new Date(data.endDate); + // Field-level form validation handles localized values; this comparison + // is for ISO API values only. + if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime())) return true; + return endDate > startDate; }, { message: 'End date must be after start date when recurrence is fixed' } ); export type ComplianceSchema = typeof complianceSchema; + +export const complianceFormSchema = (dateFormat: string) => + complianceSchema + .safeExtend({ + startDate: dateStringForFormat(dateFormat), + endDate: optionalDateStringForFormat(dateFormat) + }) + .refine( + (data) => { + if (data.recurrenceType !== 'none' || !data.startDate || !data.endDate) return true; + const startDate = parseWithFormat(data.startDate, dateFormat); + const endDate = parseWithFormat(data.endDate, dateFormat); + return !!startDate && !!endDate && endDate > startDate; + }, + { message: 'End date must be after start date when recurrence is fixed' } + ); diff --git a/src/lib/domain/fuel.ts b/src/lib/domain/fuel.ts index 0e923b96..89ca4323 100644 --- a/src/lib/domain/fuel.ts +++ b/src/lib/domain/fuel.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { apiDateString } from './shared'; +import { apiDateString, dateStringForFormat } from './shared'; export interface FuelLog { id: string | null; @@ -34,4 +34,7 @@ export const fuelSchema = z.object({ attachment: z.string().nullable() }); +export const fuelFormSchema = (dateFormat: string) => + fuelSchema.extend({ date: dateStringForFormat(dateFormat) }); + export type FuelSchema = typeof fuelSchema; diff --git a/src/lib/domain/maintenance.ts b/src/lib/domain/maintenance.ts index f1383893..3a157d93 100644 --- a/src/lib/domain/maintenance.ts +++ b/src/lib/domain/maintenance.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { apiDateString } from './shared'; +import { apiDateString, dateStringForFormat } from './shared'; export interface MaintenanceLog { id: string | null; @@ -29,4 +29,7 @@ export const maintenanceSchema = z.object({ attachment: z.string().nullable() }); +export const maintenanceFormSchema = (dateFormat: string) => + maintenanceSchema.extend({ date: dateStringForFormat(dateFormat) }); + export type MaintenanceSchema = typeof maintenanceSchema; diff --git a/src/lib/domain/reminder.ts b/src/lib/domain/reminder.ts index 65deaccd..bd5e6a02 100644 --- a/src/lib/domain/reminder.ts +++ b/src/lib/domain/reminder.ts @@ -1,5 +1,10 @@ import { z } from 'zod'; -import { apiDateString, optionalApiDateString } from './shared'; +import { + apiDateString, + dateStringForFormat, + optionalApiDateString, + optionalDateStringForFormat +} from './shared'; export const REMINDER_TYPES = { maintenance: 'maintenance', @@ -137,4 +142,10 @@ export const reminderSchema = z.object({ isCompleted: z.boolean().default(false) }); +export const reminderFormSchema = (dateFormat: string) => + reminderSchema.extend({ + dueDate: dateStringForFormat(dateFormat), + recurrenceEndDate: optionalDateStringForFormat(dateFormat) + }); + export type ReminderSchema = typeof reminderSchema; diff --git a/src/lib/domain/shared.ts b/src/lib/domain/shared.ts index 502cfd0f..c147f128 100644 --- a/src/lib/domain/shared.ts +++ b/src/lib/domain/shared.ts @@ -1,17 +1,33 @@ import { z } from 'zod'; +import { parseWithFormat } from '$lib/helper/date.helper'; +import { format, isValid, parseISO } from 'date-fns'; /** - * Validates date strings accepted by the API: anything the Date - * constructor can parse (ISO 8601 payloads from JSON-serialized Dates). + * Validates ISO 8601 date strings accepted by the API, including payloads + * produced by JSON-serialized Dates. * Display-format validation for forms lives in format.helper (client-only). */ export const apiDateString = z .string() - .refine((val) => !Number.isNaN(new Date(val).getTime()), 'Invalid date format'); + .refine((value) => isValid(parseISO(value)), 'Invalid date format'); /** Nullable/optional variant for fields that can be empty or omitted. */ export const optionalApiDateString = apiDateString.nullable().optional(); +/** Validates a date exactly as it is displayed in a localized form. */ +export const dateStringForFormat = (dateFormat: string) => + z.string().refine( + (value) => { + const parsed = parseWithFormat(value, dateFormat); + return parsed !== null && format(parsed, dateFormat) === value; + }, + { message: `Invalid date. Expected format: ${dateFormat}` } + ); + +/** Nullable/optional localized date used by form-only schemas. */ +export const optionalDateStringForFormat = (dateFormat: string) => + dateStringForFormat(dateFormat).nullable().optional(); + export type DataPoint = { x: Date | string; y: number | null; From 4fe9e0aacecba03b63ffb47fb559ec3d41276330 Mon Sep 17 00:00:00 2001 From: Niraj Yadav Date: Sat, 8 Aug 2026 15:03:52 +0530 Subject: [PATCH 2/9] fix(forms): validate localized log dates Use configured date formats across maintenance, fuel, compliance, and reminder forms. Signed-off-by: Niraj Yadav --- src/lib/components/feature/compliance/ComplianceForm.svelte | 5 +++-- src/lib/components/feature/fuel/FuelLogForm.svelte | 5 +++-- .../components/feature/maintenance/MaintenanceForm.svelte | 5 +++-- src/lib/components/feature/reminder/ReminderForm.svelte | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/lib/components/feature/compliance/ComplianceForm.svelte b/src/lib/components/feature/compliance/ComplianceForm.svelte index 593f5762..e6196e56 100644 --- a/src/lib/components/feature/compliance/ComplianceForm.svelte +++ b/src/lib/components/feature/compliance/ComplianceForm.svelte @@ -11,7 +11,7 @@ import { createSheetForm } from '$lib/composables/sheet-form.svelte'; import * as m from '$lib/paraglide/messages'; import { - complianceSchema, + complianceFormSchema, COMPLIANCE_TYPES, COMPLIANCE_RECURRENCE_TYPES, getComplianceRecurrenceTypeLabel, @@ -20,6 +20,7 @@ getComplianceDocumentNumberLabel, getComplianceIssuerLabel } from '$lib/domain/compliance'; + import configs from '$stores/config.svelte'; import { FileDropZone, AutocompleteInput } from '$lib/components/app'; import { getComplianceIssuerSuggestions } from '$lib/services/autocomplete.service'; import Banknote from '@lucide/svelte/icons/banknote'; @@ -45,7 +46,7 @@ ); const sf = createSheetForm({ - schema: complianceSchema, + schema: complianceFormSchema(configs.dateFormat), onUpdated: async ({ form: f }) => { if (f.valid) { sf.processing = true; diff --git a/src/lib/components/feature/fuel/FuelLogForm.svelte b/src/lib/components/feature/fuel/FuelLogForm.svelte index ff4fe7e7..c513b824 100644 --- a/src/lib/components/feature/fuel/FuelLogForm.svelte +++ b/src/lib/components/feature/fuel/FuelLogForm.svelte @@ -16,7 +16,8 @@ import { fuelLogStore } from '$stores/fuel-log.svelte'; import { createSheetForm } from '$lib/composables/sheet-form.svelte'; import { FileDropZone } from '$lib/components/app'; - import { fuelSchema } from '$lib/domain/fuel'; + import { fuelFormSchema } from '$lib/domain/fuel'; + import configs from '$stores/config.svelte'; import Banknote from '@lucide/svelte/icons/banknote'; import Calendar1 from '@lucide/svelte/icons/calendar-1'; import CircleGauge from '@lucide/svelte/icons/circle-gauge'; @@ -66,7 +67,7 @@ ); const sf = createSheetForm({ - schema: fuelSchema, + schema: fuelFormSchema(configs.dateFormat), validationMethod: 'onsubmit', onUpdated: async ({ form: f }) => { if (f.valid) { diff --git a/src/lib/components/feature/maintenance/MaintenanceForm.svelte b/src/lib/components/feature/maintenance/MaintenanceForm.svelte index ca9820e1..7a8726d1 100644 --- a/src/lib/components/feature/maintenance/MaintenanceForm.svelte +++ b/src/lib/components/feature/maintenance/MaintenanceForm.svelte @@ -5,7 +5,8 @@ import Input from '$appui/input.svelte'; import { Textarea } from '$ui/textarea'; import { formatDate, parseDate } from '$lib/helper/format.helper'; - import { maintenanceSchema } from '$lib/domain/maintenance'; + import { maintenanceFormSchema } from '$lib/domain/maintenance'; + import configs from '$stores/config.svelte'; import Banknote from '@lucide/svelte/icons/banknote'; import Hammer from '@lucide/svelte/icons/hammer'; import CircleGauge from '@lucide/svelte/icons/circle-gauge'; @@ -34,7 +35,7 @@ ); const sf = createSheetForm({ - schema: maintenanceSchema, + schema: maintenanceFormSchema(configs.dateFormat), onUpdated: async ({ form: f }) => { if (f.valid) { sf.processing = true; diff --git a/src/lib/components/feature/reminder/ReminderForm.svelte b/src/lib/components/feature/reminder/ReminderForm.svelte index c17f82a2..b72bff52 100644 --- a/src/lib/components/feature/reminder/ReminderForm.svelte +++ b/src/lib/components/feature/reminder/ReminderForm.svelte @@ -7,11 +7,12 @@ REMINDER_TYPES, REMINDER_SCHEDULES, REMINDER_RECURRENCE_TYPES, - reminderSchema, + reminderFormSchema, getReminderScheduleLabel, getRecurrenceTypeLabel, getReminderTypeLabel } from '$lib/domain/reminder'; + import configs from '$stores/config.svelte'; import { createSheetForm } from '$lib/composables/sheet-form.svelte'; import { sheetStore } from '$stores/sheet.svelte'; import SubmitButton from '$appui/SubmitButton.svelte'; @@ -35,7 +36,7 @@ let { data }: { data?: Partial } = $props(); const sf = createSheetForm({ - schema: reminderSchema, + schema: reminderFormSchema(configs.dateFormat), onUpdated: async ({ form: f }) => { if (f.valid) { sf.processing = true; From 3dc22a27bf212290f69086f47e16c9972b08a3fe Mon Sep 17 00:00:00 2001 From: Niraj Yadav Date: Sat, 8 Aug 2026 15:26:36 +0530 Subject: [PATCH 3/9] fix(fuel): use configured currency for total spent Format fuel spending with the user's currency and locale settings. Signed-off-by: Niraj Yadav --- src/routes/(app)/fuel/+page.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/(app)/fuel/+page.svelte b/src/routes/(app)/fuel/+page.svelte index a4365f31..dbc4e0c9 100644 --- a/src/routes/(app)/fuel/+page.svelte +++ b/src/routes/(app)/fuel/+page.svelte @@ -7,7 +7,7 @@ import { fuelLogStore } from '$stores/fuel-log.svelte'; import { chartStore } from '$stores/chart.svelte'; import { ACCENT } from '$lib/helper/accent-color.helper'; - import { formatMileage } from '$lib/helper/format.helper'; + import { formatCurrency, formatMileage } from '$lib/helper/format.helper'; import VehicleTrendChart from '$feature/overview/VehicleTrendChart.svelte'; import FuelLogTab from '$feature/fuel/FuelLogTab.svelte'; import { Features } from '$lib/helper/feature.helper'; @@ -52,7 +52,7 @@ 0 ? `$${totalCost.toFixed(2)}` : '--'} + value={totalCost > 0 ? formatCurrency(totalCost) : '--'} color={ACCENT.ochre.gradient} /> Date: Sat, 8 Aug 2026 15:45:55 +0530 Subject: [PATCH 4/9] fix(charts): use configured currency Format expense chart axes and tooltips with the user's currency settings. Signed-off-by: Niraj Yadav --- src/lib/components/dashboard/StackedAreaChart.svelte | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/components/dashboard/StackedAreaChart.svelte b/src/lib/components/dashboard/StackedAreaChart.svelte index 3ba00cee..e68e65fc 100644 --- a/src/lib/components/dashboard/StackedAreaChart.svelte +++ b/src/lib/components/dashboard/StackedAreaChart.svelte @@ -9,6 +9,7 @@ import LegendInfoGroup from '$appui/LegendInfoGroup.svelte'; import CircleSlash2 from '@lucide/svelte/icons/circle-slash-2'; import Skeleton from '$lib/components/ui/skeleton/skeleton.svelte'; + import { formatCurrency } from '$lib/helper/format.helper'; let { data, @@ -38,7 +39,7 @@ format: (v: Date) => v.toLocaleDateString('en-IN', { month: 'short', year: '2-digit' }) }, yAxis: { - format: (v: number) => `$${v.toFixed(0)}` + format: (v: number) => formatCurrency(v) }, grid: { style: 'stroke-dasharray: 2', @@ -104,7 +105,7 @@ {#snippet formatter({ value, name })} {name} - {typeof value === 'number' ? `$${value.toFixed(2)}` : value} + {typeof value === 'number' ? formatCurrency(value) : value} {/snippet} From 9d263a6facc3cd53d912b8c33a85d0a72e77afd0 Mon Sep 17 00:00:00 2001 From: Niraj Yadav Date: Mon, 10 Aug 2026 18:12:18 +0530 Subject: [PATCH 5/9] fix(validation): handle localized compliance date ranges Signed-off-by: Niraj Yadav --- src/__tests__/date-validation.test.ts | 21 +++++++++++++++++++++ src/lib/domain/compliance.ts | 16 ---------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/__tests__/date-validation.test.ts b/src/__tests__/date-validation.test.ts index 546bc09c..a247b028 100644 --- a/src/__tests__/date-validation.test.ts +++ b/src/__tests__/date-validation.test.ts @@ -64,4 +64,25 @@ describe('localized date validation', () => { complianceFormSchema('dd/MM/yyyy').safeParse({ ...base, endDate: '12/08/2026' }).success ).toBe(false); }); + + it('does not reverse valid ambiguous dates in day-first formats', () => { + const base = { + id: null, + vehicleId: '123e4567-e89b-42d3-a456-426614174000', + type: 'insurance' as const, + otherLabel: null, + documentNumber: 'ABC123', + issuer: 'Insurer', + startDate: '10/03/2026', + recurrenceType: 'none' as const, + recurrenceInterval: 1, + cost: null, + notes: null, + attachment: null + }; + + expect( + complianceFormSchema('dd/MM/yyyy').safeParse({ ...base, endDate: '03/10/2026' }).success + ).toBe(true); + }); }); diff --git a/src/lib/domain/compliance.ts b/src/lib/domain/compliance.ts index 71f1d14c..b7186f25 100644 --- a/src/lib/domain/compliance.ts +++ b/src/lib/domain/compliance.ts @@ -194,22 +194,6 @@ export const complianceSchema = z return !!data.otherLabel && data.otherLabel.trim().length > 0; }, { message: 'Please name the compliance type', path: ['otherLabel'] } - ) - .refine( - (data) => { - if (data.recurrenceType === undefined) return true; - if (data.recurrenceType !== 'none') return true; - if (data.endDate === undefined) return true; - if (!data.endDate) return false; - if (!data.startDate) return true; - const startDate = new Date(data.startDate); - const endDate = new Date(data.endDate); - // Field-level form validation handles localized values; this comparison - // is for ISO API values only. - if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime())) return true; - return endDate > startDate; - }, - { message: 'End date must be after start date when recurrence is fixed' } ); export type ComplianceSchema = typeof complianceSchema; From 25f99907f7453d2fed4c0dd1c322e0996d386d4d Mon Sep 17 00:00:00 2001 From: Sasha Date: Fri, 14 Aug 2026 18:30:43 +0300 Subject: [PATCH 6/9] Add Russian language support and update README --- README.md | 2 +- docs/i18n.md | 6 +- i18n/messages/ru.json | 813 +++++++++++++++++++++++++ i18n/project.inlang/settings.json | 2 +- src/lib/helper/settings-form.helper.ts | 3 +- 5 files changed, 820 insertions(+), 6 deletions(-) create mode 100644 i18n/messages/ru.json diff --git a/README.md b/README.md index 8ad5399d..c9e1404c 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Run it on a Raspberry Pi, a home server, or a $5 VPS. Your data stays yours. - **Expenses & reports** — See what your vehicles actually cost you. - **Dashboard** — A fleet-wide overview with widgets you can rearrange to your liking. - **Auth & feature toggles** — Username/password login with sessions, and the ability to turn off features you don't need. -- **10 languages** — English, Hindi, Spanish, French, German, Italian, Arabic, Romanian, Hungarian, and Finnish. +- **11 languages** — English, Hindi, Spanish, French, German, Italian, Arabic, Romanian, Hungarian, Finnish, and Russian. ## Tech stack diff --git a/docs/i18n.md b/docs/i18n.md index b4d86f9e..1559cc3c 100644 --- a/docs/i18n.md +++ b/docs/i18n.md @@ -22,9 +22,9 @@ Tracktor uses Paraglide (inlang) with the Svelte 5 addon for runtime-localized U ## Adding a new language -1. Add the language in your Paraglide source/messages `i18n/messages` and regenerate the compiled outputs under `src/lib/paraglide/messages/`. -2. Ensure the new language code is included in Paraglide's generated `locales` array (in `src/lib/paraglide/runtime.js`). -3. Optionally add a human-readable label in `src/lib/components/feature/settings/SettingsForm.svelte` in the `localeLabels` map. +1. Add a message file for the language in `i18n/messages/.json`, using `en.json` as the reference for keys. +2. Add the locale code to the `locales` array in `i18n/project.inlang/settings.json`. The Paraglide vite plugin regenerates `src/lib/paraglide/` (including the `locales` array) on the next `vite dev`/`vite build`. +3. Optionally add a human-readable label in the `localeLabels` map in `src/lib/helper/settings-form.helper.ts`. 4. Provide translations for your messages via inlang tooling (VS Code Sherlock, Fink, etc.). ## Notes diff --git a/i18n/messages/ru.json b/i18n/messages/ru.json new file mode 100644 index 00000000..98436267 --- /dev/null +++ b/i18n/messages/ru.json @@ -0,0 +1,813 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "hello_world": "Привет, {name} из ru!", + "app_name": "Tracktor", + "app_title": "Ваш гараж", + "app_new_update_available": "Доступно обновление. Перезагрузка…", + "app_add_vehicle": "Добавить автомобиль", + "vehicle_scope_all": "Все автомобили", + "vehicle_scope_manage": "Управление автомобилями", + "form_vehicle_label": "Автомобиль", + "form_vehicle_desc": "К какому автомобилю относится запись", + "app_empty_select_message": "Выберите автомобиль, чтобы посмотреть подробности", + "app_empty_select_hint": "Выберите автомобиль из гаража выше, чтобы загрузить его панель.", + "demo_banner": "Это демонстрационная версия. Данные периодически сбрасываются и не сохраняются навсегда. Не вводите личную информацию.", + "default_login": "Логин по умолчанию: demo / demo", + "auth_username": "Имя пользователя", + "auth_username_placeholder": "имя пользователя", + "auth_password": "Пароль", + "auth_password_placeholder": "********", + "auth_confirm_password": "Подтвердите пароль", + "auth_login_button": "Войти", + "auth_signup_button": "Зарегистрироваться", + "auth_login_loading": "Выполняется вход…", + "auth_signup_loading": "Создание аккаунта…", + "auth_password_mismatch": "Пароли не совпадают!", + "auth_login_title": "С возвращением", + "auth_login_subtitle": "Войдите, чтобы держать под контролем автомобили, заправки и документы.", + "settings_tab_personalization": "Персонализация", + "settings_tab_interface": "Интерфейс", + "settings_tab_localization": "Локализация", + "settings_tab_advanced": "Дополнительно", + "settings_tab_features": "Функции", + "settings_tab_units": "Единицы измерения", + "settings_title": "Настройки", + "settings_page_description": "Настройте внешний вид, язык, региональные форматы и поведение интерфейса.", + "settings_label_date_format": "Формат даты", + "settings_label_locale": "Язык", + "settings_label_timezone": "Часовой пояс", + "settings_label_currency": "Валюта", + "settings_label_unit_distance": "Единица расстояния", + "settings_label_unit_volume": "Единица объёма топлива", + "settings_label_theme": "Тема", + "settings_label_dark_mode": "Стиль тёмной темы", + "settings_label_custom_css": "Пользовательский CSS", + "settings_update_button": "Сохранить настройки", + "settings_select_unit_system": "Выберите систему единиц", + "settings_select_theme": "Выберите тему", + "settings_select_dark_mode": "Выберите стиль тёмной темы", + "settings_desc_date_format": "Выберите предпочитаемый формат даты", + "settings_desc_locale": "Выберите язык интерфейса", + "settings_desc_timezone": "Выберите часовой пояс для отображения дат", + "settings_desc_currency": "Выберите предпочитаемую валюту", + "settings_desc_unit_distance": "Единица измерения расстояния", + "settings_desc_unit_volume": "Единица измерения объёма", + "settings_label_mileage_format": "Формат отображения расхода", + "settings_desc_mileage_format": "Выберите, как отображать расход топлива", + "settings_mileage_format_distance_per_fuel": "Расстояние на топливо (например, км/л, mpg)", + "settings_mileage_format_fuel_per_distance": "Топливо на расстояние (например, л/100 км)", + "settings_mileage_format_uk_mpg": "UK MPG (мили на имперский галлон)", + "settings_desc_theme": "Выберите предпочитаемую тему", + "settings_desc_dark_mode": "Выберите контрастность для тёмной темы", + "settings_desc_custom_css": "CSS-стили для настройки интерфейса", + "settings_select_language": "Выберите язык", + "settings_updated_success": "Настройки успешно сохранены!", + "common_example_prefix": "Пример — ", + "common_invalid_format": "Неверный формат…", + "common_kilometer": "Километры", + "common_mile": "Мили", + "common_litre": "Литр", + "common_gallon": "Галлон", + "common_submit": "Сохранить", + "common_details": "Подробности", + "common_close": "Закрыть", + "common_view": "Открыть", + "common_view_all": "Показать все", + "common_view_less": "Свернуть", + "common_loading": "Загрузка…", + "common_add": "Добавить", + "common_yes": "Да", + "common_no": "Нет", + "common_cancel": "Отмена", + "common_confirm": "Подтвердить", + "common_continue": "Продолжить", + "common_skip": "Пропустить", + "delete_dialog_title": "Удаление", + "delete_dialog_message": "Вы уверены, что хотите удалить?", + "common_select_column": "Выбрать столбец", + "common_import": "Импорт", + "common_search": "Поиск", + "common_columns": "Столбцы", + "common_rows_per_page": "Строк на странице", + "common_no_data_available": "Нет данных", + "common_no_records_found": "Записи не найдены", + "common_add_new": "Добавить", + "common_no_match_found": "Совпадений не найдено", + "common_search_placeholder": "Поиск: {name}", + "common_select_placeholder": "Выберите {name}…", + "common_date_from": "С", + "common_date_to": "По", + "common_export_csv": "Экспорт в CSV", + "nav_overview": "Обзор", + "nav_fuel_logs": "Заправки", + "nav_maintenance": "Обслуживание", + "nav_reminders": "Напоминания", + "tools_export_data": "Экспорт данных", + "tools_import_data": "Импорт данных", + "vehicle_form_make_label": "Марка", + "vehicle_form_make_desc": "Производитель автомобиля", + "vehicle_form_model_label": "Модель", + "vehicle_form_model_desc": "Модель автомобиля", + "vehicle_form_year_label": "Год", + "vehicle_form_year_desc": "Год выпуска", + "vehicle_form_color_label": "Цвет", + "vehicle_form_color_desc": "Цвет автомобиля", + "vehicle_form_fuel_type_label": "Тип топлива", + "vehicle_form_fuel_type_desc": "Тип топлива, на котором работает автомобиль", + "vehicle_form_fuel_type_placeholder": "Выберите тип топлива", + "vehicle_form_vehicle_type_label": "Тип транспорта", + "vehicle_form_vehicle_type_desc": "Категория транспортного средства", + "vehicle_form_vehicle_type_placeholder": "Выберите тип транспорта", + "vehicle_form_odometer_label": "Одометр", + "vehicle_form_odometer_desc": "Текущие показания одометра", + "vehicle_form_license_label": "Госномер", + "vehicle_form_license_desc": "Регистрационный номер автомобиля", + "vehicle_form_vin_label": "VIN", + "vehicle_form_vin_desc": "Идентификационный номер автомобиля", + "vehicle_toast_saved": "Автомобиль успешно сохранён", + "vehicle_toast_updated": "Автомобиль успешно обновлён", + "vehicle_toast_error_prefix": "Ошибка при сохранении: ", + "vehicle_list_empty": "Здесь пока пусто. Добавьте первый автомобиль, чтобы начать.", + "vehicle_delete_success": "Автомобиль удалён.", + "vehicle_delete_error": "При удалении автомобиля произошла ошибка.", + "vehicle_action_add_fuel_log": "Добавить заправку", + "vehicle_action_add_maintenance_log": "Добавить запись об обслуживании", + "vehicle_action_add_reminder": "Добавить напоминание", + "vehicle_action_more_info": "Подробнее", + "vehicle_action_update_vehicle": "Изменить автомобиль", + "vehicle_action_edit": "Изменить", + "vehicle_action_delete": "Удалить", + "tools_export_encrypt_label": "Шифровать экспортируемые данные", + "tools_export_password_label": "Пароль шифрования", + "tools_export_password_placeholder": "Введите пароль для шифрования", + "tools_export_password_hint": "Сохраните этот пароль — он понадобится для расшифровки данных при импорте.", + "tools_export_status_exporting": "Экспорт…", + "tools_export_button": "Экспортировать базу", + "tools_export_info_title": "Информация об экспорте", + "tools_export_info_bullet_1": "Экспортируются все таблицы и данные базы", + "tools_export_info_bullet_2": "Включая автомобили, заправки, записи об обслуживании и прочее", + "tools_export_info_bullet_3": "Шифрование по желанию — для защиты конфиденциальных данных", + "tools_export_info_bullet_4": "Скачивается в виде JSON-файла", + "tools_export_success": "Данные успешно экспортированы", + "tools_export_error": "Не удалось экспортировать данные", + "tools_import_upload_label": "Загрузить JSON-файл", + "tools_import_paste_label": "Или вставить JSON-данные", + "tools_import_paste_placeholder": "Вставьте сюда экспортированные JSON-данные…", + "tools_import_password_label": "Пароль расшифровки (если данные зашифрованы)", + "tools_import_password_placeholder": "Введите пароль, если данные зашифрованы", + "tools_import_status_importing": "Импорт…", + "tools_import_button": "Импортировать базу", + "tools_import_warning_title": "⚠️ Внимание при импорте", + "tools_import_warning_bullet_1": "Это заменит ВСЕ существующие данные", + "tools_import_warning_bullet_2": "Сначала обязательно сделайте резервную копию текущих данных", + "tools_import_warning_bullet_3": "Импорт нельзя отменить", + "tools_import_warning_bullet_4": "Убедитесь, что формат JSON корректен", + "tools_import_success": "Данные успешно импортированы", + "tools_import_error": "Не удалось импортировать данные", + "tools_import_invalid_json": "Неверный формат JSON", + "feature_overview_disabled_title": "Раздел «Обзор» отключён", + "feature_overview_disabled_hint": "Включите эту функцию в настройках, чтобы видеть обзорную панель", + "feature_fuel_disabled_title": "Раздел «Заправки» отключён", + "feature_fuel_disabled_hint": "Включите эту функцию в настройках, чтобы отслеживать расход топлива", + "feature_maintenance_disabled_title": "Раздел «Обслуживание» отключён", + "feature_maintenance_disabled_hint": "Включите эту функцию в настройках, чтобы вести записи об обслуживании", + "feature_reminders_disabled_title": "Раздел «Напоминания» отключён", + "feature_reminders_disabled_hint": "Включите эту функцию в настройках, чтобы управлять напоминаниями", + "overview_chart_no_data": "Нет данных", + "overview_chart_cost_label": "Расходы", + "overview_chart_cost_title": "Расходы по времени ({currency})", + "overview_chart_mileage_label": "Расход", + "overview_chart_mileage_title": "Расход топлива по времени ({unit})", + "fuel_import_title": "Импорт заправок", + "fuel_add_title": "Добавить заправку", + "col_date": "Дата", + "col_odometer": "Одометр", + "col_distance_driven": "Пройдено", + "col_filled": "Полный бак", + "col_missed_last": "Пропуск записей", + "col_fuel_amount": "Объём топлива", + "col_cost": "Стоимость", + "col_mileage": "Расход", + "col_notes": "Заметки", + "col_attachment": "Вложение", + "col_no_end_date": "Без даты окончания", + "fuel_volume_label_fuel": "Объём топлива", + "fuel_volume_label_energy": "Энергия", + "fuel_empty_list": "Для этого автомобиля нет записей о заправках.", + "form_date": "Дата", + "form_date_desc": "Дата заправки", + "form_odometer": "Одометр", + "form_odometer_desc": "Текущие показания одометра", + "form_volume_fuel": "Объём топлива", + "form_volume_energy": "Полученная энергия", + "form_rate": "Цена за единицу", + "form_cost": "Стоимость", + "form_cost_desc": "Стоимость заправки", + "form_cost_desc_ev": "Стоимость зарядки", + "form_full_charge": "Полный заряд", + "form_full_tank": "Полный бак", + "form_full_charge_desc": "Батарея заряжена полностью?", + "form_full_tank_desc": "Бак заправлен до полного?", + "form_missed_last": "Пропуск записей", + "form_missed_last_desc": "Были ли пропущены предыдущие записи?", + "form_notes": "Заметки", + "form_notes_placeholder": "Добавьте подробности, если есть…", + "form_attachment": "Вложение", + "fuel_toast_saved": "Заправка успешно сохранена!", + "fuel_toast_updated": "Заправка успешно обновлена!", + "fuel_toast_error_prefix": "Ошибка при сохранении: ", + "notifications_title": "Уведомления", + "notifications_new": "новых", + "notifications_syncing": "Загрузка свежих данных…", + "notifications_caught_up": "Новых уведомлений нет.", + "notifications_section_reminders": "Напоминания", + "notifications_section_alerts": "Оповещения о документах", + "notifications_mark_done_title": "Отметить напоминание как выполненное", + "notifications_mark_done_aria": "Отметить напоминание «{type}» как выполненное", + "notifications_mark_all_read_title": "Отметить все как прочитанные", + "notifications_mark_all_read_aria": "Отметить все уведомления как прочитанные", + "notifications_overdue_days": "Просрочено на {days} дн.", + "notifications_due_today": "Срок сегодня", + "notifications_due_tomorrow": "Срок завтра", + "notifications_due_in_days": "Срок через {days} дн.", + "alerts_status_expired": "Истёк", + "alerts_status_expiring": "Истекает", + "alerts_status_valid": "Действует", + "alerts_status_missing": "Отсутствует", + "notifications_expires": "Истекает", + "notifications_error_no_id": "Невозможно обновить напоминание без идентификатора.", + "notifications_error_update_failed": "Не удалось обновить напоминание.", + "notifications_success_marked_done": "Напоминание отмечено как выполненное.", + "notifications_severity_overdue": "Просрочено", + "notifications_severity_due_soon": "Скоро срок", + "notifications_severity_upcoming": "Предстоит", + "settings_custom_css_placeholder": "Добавьте свой CSS здесь…", + "settings_features_intro": "Включайте и отключайте функции под свои задачи", + "feature_label_fuel": "Заправки", + "feature_desc_fuel": "Учёт расхода топлива и истории заправок", + "feature_label_maintenance": "Обслуживание", + "feature_desc_maintenance": "Записи и планирование работ по обслуживанию", + "feature_label_reminders": "Напоминания", + "feature_desc_reminders": "Напоминания о важных событиях по автомобилю", + "feature_label_overview": "Обзор", + "feature_desc_overview": "Обзорная панель с ключевыми показателями по автомобилю", + "settings_error_date_format_invalid": "Неверный формат", + "settings_error_timezone_invalid": "Недопустимый часовой пояс.", + "settings_error_currency_required": "Укажите валюту", + "maintenance_form_attachment_label": "Вложение", + "maintenance_form_attachment_desc": "Загрузите чек или документ об обслуживании", + "maintenance_form_date_label": "Дата", + "maintenance_form_date_desc": "Дата обслуживания", + "maintenance_form_odometer_label": "Одометр", + "maintenance_form_odometer_desc": "Текущие показания одометра", + "maintenance_form_service_center_label": "Сервис", + "maintenance_form_service_center_desc": "Название сервисного центра", + "maintenance_form_cost_label": "Стоимость", + "maintenance_form_cost_desc": "Стоимость обслуживания", + "maintenance_form_notes_label": "Заметки", + "maintenance_form_notes_desc": "Дополнительные сведения", + "maintenance_form_notes_placeholder": "Добавьте подробности, если есть…", + "maintenance_toast_saved": "Запись об обслуживании сохранена", + "maintenance_toast_updated": "Запись об обслуживании обновлена", + "maintenance_toast_error_prefix": "Ошибка при сохранении: ", + "maintenance_form_error_fix": "Исправьте ошибки в форме перед отправкой.", + "maintenance_list_empty": "Для этого автомобиля нет записей об обслуживании.", + "maintenance_col_service_center": "Сервис", + "maintenance_menu_open": "Открыть меню", + "maintenance_menu_edit": "Изменить", + "maintenance_menu_delete": "Удалить", + "maintenance_menu_sheet_title": "Изменить запись об обслуживании", + "maintenance_tab_title": "История обслуживания", + "maintenance_add_action": "Добавить запись об обслуживании", + "maintenance_export_pdf": "Экспорт в PDF", + "maintenance_delete_success": "Запись об обслуживании удалена.", + "maintenance_delete_error": "При удалении записи об обслуживании произошла ошибка.", + "reminder_form_due_date_label": "Срок", + "reminder_form_due_date_desc": "Когда должно сработать напоминание?", + "reminder_form_type_label": "Тип", + "reminder_form_type_desc": "Выберите тип напоминания", + "reminder_form_schedule_label": "Когда напомнить", + "reminder_form_schedule_desc": "За сколько напомнить о сроке?", + "reminder_form_recurrence_type_label": "Повторение", + "reminder_form_recurrence_type_desc": "Должно ли напоминание повторяться?", + "reminder_form_recurrence_interval_label": "Повторять каждые", + "reminder_form_recurrence_interval_desc": "Частота повторения", + "reminder_form_recurrence_end_date_label": "Дата окончания", + "reminder_form_recurrence_end_date_desc": "Когда прекратить повторения? (необязательно)", + "reminder_form_note_label": "Заметка", + "reminder_form_note_desc": "Добавьте подробности", + "reminder_form_note_placeholder": "Опишите, на что обратить внимание", + "reminder_form_is_completed_label": "Отметить как выполненное", + "reminder_toast_created": "Напоминание создано.", + "reminder_toast_updated": "Напоминание обновлено", + "reminder_toast_error_prefix": "Ошибка при сохранении: ", + "reminder_list_empty": "Напоминаний пока нет. Создайте первое, чтобы не пропустить сроки продления.", + "reminder_list_select_vehicle": "Выберите автомобиль, чтобы посмотреть напоминания.", + "reminder_list_select_hint": "Выберите автомобиль выше, чтобы загрузить его предстоящие напоминания.", + "reminder_col_due_date": "Срок", + "reminder_col_reminder_schedule": "Когда напомнить", + "reminder_col_recurrence": "Повторение", + "reminder_col_note": "Заметки", + "reminder_menu_toggle_done": "Отметить как «{status}»", + "reminder_menu_toggle_done_done": "Отметить как невыполненное", + "reminder_menu_toggle_done_pending": "Отметить как выполненное", + "reminder_menu_edit": "Изменить", + "reminder_menu_delete": "Удалить", + "reminder_menu_open": "Открыть меню", + "reminder_menu_sheet_title": "Изменить напоминание", + "reminder_add_action": "Добавить напоминание", + "reminder_delete_success": "Напоминание удалено.", + "reminder_delete_error": "При удалении напоминания произошла ошибка.", + "reminder_status_completed": "Выполнено", + "reminder_status_pending": "Ожидает", + "reminder_status_overdue": "Просрочено", + "reminder_status_error": "Не удалось изменить статус напоминания.", + "reminder_toast_error_fallback": "Не удалось сохранить напоминание.", + "settings_sheet_title": "Настройки", + "profile_menu_item": "Профиль", + "profile_sheet_title": "Профиль", + "profile_sheet_desc": "Измените имя пользователя и пароль", + "profile_username": "Имя пользователя", + "profile_username_desc": "Ваше отображаемое имя", + "profile_password_hint": "Оставьте поля пароля пустыми, чтобы сохранить текущий пароль", + "profile_current_password": "Текущий пароль", + "profile_current_password_desc": "Требуется для смены пароля", + "profile_new_password": "Новый пароль", + "profile_new_password_desc": "Минимум 6 символов", + "profile_confirm_password": "Подтвердите пароль", + "profile_confirm_password_desc": "Введите новый пароль ещё раз", + "profile_update_button": "Обновить профиль", + "tools_menu": "Инструменты", + "data_export_import_menu_item": "Экспорт и импорт данных", + "data_export_import_sheet_title": "Экспорт и импорт данных", + "data_export_import_sheet_desc": "Экспортируйте или импортируйте базу данных, при желании с шифрованием", + "logout_menu_item": "Выйти", + "custom_fields_label": "Дополнительные поля", + "custom_fields_add_button": "Добавить поле", + "custom_fields_name_placeholder": "Название поля", + "custom_fields_value_placeholder": "Значение поля", + "custom_fields_remove_aria": "Удалить поле", + "custom_fields_empty_message": "Дополнительных полей нет. Нажмите «Добавить поле», чтобы начать.", + "vehicle_details_vin": "VIN", + "vehicle_details_not_specified": "Не указано", + "vehicle_details_not_available": "Недоступно", + "vehicle_details_section_title": "Подробности", + "vehicle_details_license_plate": "Госномер", + "vehicle_details_fuel_type": "Тип топлива", + "vehicle_details_odometer": "Одометр", + "vehicle_details_not_recorded": "Нет данных", + "vehicle_details_color": "Цвет", + "vehicle_details_year": "Год", + "vehicle_type_car": "Легковой автомобиль", + "vehicle_type_motorcycle": "Мотоцикл", + "vehicle_type_scooter": "Скутер", + "vehicle_type_truck": "Грузовик", + "vehicle_type_van": "Фургон", + "vehicle_type_bus": "Автобус", + "vehicle_type_farm_vehicle": "Сельхозтехника", + "vehicle_type_yacht": "Яхта", + "vehicle_type_rv": "Дом на колёсах / прицеп", + "vehicle_type_other": "Другое", + "fuel_type_diesel": "Дизель", + "fuel_type_petrol": "Бензин", + "fuel_type_electric": "Электро", + "fuel_type_lpg": "Пропан (LPG)", + "fuel_type_cng": "Метан (CNG)", + "fuel_type_ev": "Электромобиль (EV)", + "reminder_schedule_same_day": "В день срока", + "reminder_schedule_one_day_before": "За 1 день", + "reminder_schedule_three_days_before": "За 3 дня", + "reminder_schedule_one_week_before": "За неделю", + "reminder_schedule_one_month_before": "За месяц", + "recurrence_type_none": "Без повторения", + "recurrence_type_daily": "Ежедневно", + "recurrence_type_weekly": "Еженедельно", + "recurrence_type_monthly": "Ежемесячно", + "recurrence_type_yearly": "Ежегодно", + "recurrence_every": "каждые", + "recurrence_renew_every": "Продлевать каждые", + "recurrence_interval_days": "дн.", + "recurrence_interval_weeks": "нед.", + "recurrence_interval_months": "мес.", + "recurrence_interval_years": "лет", + "recurrence_until": "До", + "file_drop_existing_note": "Прикреплённый файл (нажмите, чтобы открыть)", + "fuel_import_step_1_title": "Шаг 1: загрузка CSV-файла", + "fuel_import_step_1_desc": "Выберите текстовый файл с разделителями, содержащий данные о заправках, чтобы начать импорт.", + "fuel_import_drop_placeholder": "Перетащите сюда текстовый файл с разделителями или нажмите для выбора", + "fuel_import_headers_checkbox": "Первая строка содержит заголовки", + "fuel_import_delimiter_title": "Разделитель", + "fuel_import_delimiter_desc": "Выберите символ, разделяющий поля", + "fuel_import_date_format_title": "Формат даты", + "fuel_import_date_format_desc": "Укажите формат, в котором записаны даты в вашем CSV-файле.", + "fuel_import_error_no_headers": "Заголовки не найдены. Обновите csv.helper.ts, чтобы он возвращал заголовки.", + "fuel_import_step_2_title": "Шаг 2: сопоставление столбцов", + "fuel_import_step_2_desc": "Сопоставьте столбцы CSV-файла с соответствующими полями записи о заправке. Обязательные поля отмечены знаком *.", + "fuel_import_step_3_title": "Шаг 3: предпросмотр и импорт", + "fuel_import_step_3_desc": "Проверьте, как выглядят данные перед импортом.", + "fuel_import_no_preview": "Данных для предпросмотра пока нет. Реализуйте разбор в csv.helper.ts, чтобы заполнить строки.", + "fuel_import_success": "Импортировано заправок: {count}.", + "fuel_import_failed_count": "Импортировано: {imported}, с ошибкой: {failed}", + "fuel_import_error_generic": "Не удалось импортировать заправки.", + "fuel_import_vehicle_label": "Автомобиль:", + "fuel_import_delimiter_comma": "Запятая ( , )", + "fuel_import_delimiter_semicolon": "Точка с запятой ( ; )", + "fuel_import_delimiter_tab": "Табуляция ( \\t )", + "fuel_import_delimiter_pipe": "Вертикальная черта ( | )", + "fuel_import_delimiter_custom": "Свой", + "fuel_import_date_error": "В некоторых строках дата не соответствует формату «{format}»", + "fuel_import_date_format_placeholder": "например, MM/DD/YYYY", + "fuel_import_date_invalid": "Неверная дата", + "fuel_import_no_vehicle": "Автомобиль не выбран", + "fuel_import_col_date_hint": "Дата заправки", + "fuel_import_col_odometer_hint": "Показания одометра на момент заправки", + "fuel_import_col_fuel_hint": "Объём топлива или полученная энергия", + "fuel_import_col_cost_hint": "Общая стоимость записи", + "fuel_import_col_filled_hint": "Это полный бак или полный заряд?", + "fuel_import_col_missed_hint": "Была ли пропущена предыдущая запись?", + "fuel_import_col_notes_hint": "Любые дополнительные заметки", + "autocomplete_placeholder": "Введите или выберите…", + "autocomplete_loading": "Загрузка подсказок…", + "autocomplete_no_results": "Подсказок нет. Можно ввести своё значение.", + "input_date_placeholder": "Выберите дату", + "loading_default_message": "Загрузка…", + "dropzone_placeholder_image": "Нажмите или перетащите изображение для загрузки", + "dropzone_placeholder_attachment": "Перетащите файл сюда или нажмите для выбора", + "dropzone_placeholder_default": "Нажмите или перетащите файлы для загрузки", + "dropzone_error_single_file": "Загрузите только один файл.", + "dropzone_error_file_size": "Размер файла превышает лимит {size}.", + "dropzone_unknown_file": "Неизвестный файл", + "dropzone_uploading": "Загрузка…", + "dropzone_supports": "Поддерживаются: {types}", + "dropzone_max_size": "Макс. размер: {size}", + "dropzone_error_file_type": "Недопустимый тип файла", + "dropzone_hint_accept_limit": "{types} до {size}", + "vehicle_details_color_aria": "Цвет", + "vehicle_details_close_aria": "Закрыть", + "attachment_link_view_title": "Открыть вложение", + "file_preview_not_available": "Предпросмотр недоступен", + "file_preview_download_hint": "Этот тип файла нельзя посмотреть в браузере. Скачайте его для просмотра.", + "file_preview_download_button": "Скачать файл", + "file_preview_aria_download": "Скачать", + "file_preview_aria_close": "Закрыть", + "theme_toggle_label": "Переключить тему", + "fuel_log_edit": "Изменить", + "fuel_log_delete": "Удалить", + "fuel_log_menu_open": "Открыть меню", + "fuel_log_delete_success": "Запись о заправке удалена", + "fuel_log_menu_sheet_title": "Изменить запись о заправке", + "fuel_log_delete_error": "При удалении записи о заправке произошла ошибка.", + "color_picker_label": "Выберите цвет", + "reminder_type_maintenance": "Обслуживание", + "reminder_type_insurance": "Продление страховки", + "reminder_type_pollution": "Экологический контроль", + "reminder_type_registration": "Регистрация / налог", + "reminder_type_inspection": "Техосмотр", + "reminder_type_custom": "Другое", + "alert_status_expired_ago": "{label}: истёк {days} дн. назад", + "alert_status_expires_in": "{label}: истекает через {days} дн.", + "alert_status_valid_for": "{label}: действует ещё {days} дн.", + "alert_record_not_found": "Запись «{label}» не найдена. Добавьте данные, чтобы не пропустить сроки.", + "settings_error_format_not_valid": "Неверный формат", + "common_kilogram_unit": "Килограмм (кг)", + "common_pound_unit": "Фунт (lb)", + "settings_section_fuel_types": "Типы топлива", + "settings_section_fuel_types_desc": "Выберите единицу измерения для каждого вида топлива.", + "fuel_type_petrol_diesel": "Бензин / дизель", + "theme_slate": "Сланцевая", + "theme_stone": "Каменная", + "theme_red": "Красная", + "theme_rose": "Розовая", + "theme_blue": "Синяя", + "theme_green": "Зелёная", + "theme_purple": "Фиолетовая", + "theme_orange": "Оранжевая", + "theme_yellow": "Жёлтая", + "theme_teal": "Бирюзовая", + "theme_indigo": "Индиго", + "theme_pink": "Фуксия", + "dark_variant_default": "Обычный", + "dark_variant_dim": "Приглушённый", + "dark_variant_oled": "OLED (чистый чёрный)", + "settings_tab_notifications": "Уведомления", + "settings_personalization_desc": "Настройте оформление: темы, язык и форматы.", + "settings_section_general": "Основное", + "settings_section_general_desc": "Настройте внешний вид, локализацию и форматы отображения", + "settings_units_desc": "Настройте единицы измерения расстояния, объёма и типов топлива.", + "settings_section_units": "Единицы измерения", + "settings_section_units_desc": "Выберите единицы для расстояния, расхода и типов топлива", + "settings_section_feature_flags": "Функции приложения", + "settings_section_feature_flags_desc": "Включайте и отключайте основные модули приложения", + "settings_notifications_desc": "Настройте подписки провайдеров и время ежедневной отправки уведомлений.", + "settings_localization_desc": "Задайте язык и региональные настройки.", + "settings_advanced_desc": "Тонкая настройка интерфейса с помощью своих стилей.", + "settings_nav_desc_personalization": "Тема, отображение и стиль", + "settings_nav_desc_localization": "Язык и региональные форматы", + "settings_nav_desc_advanced": "Свой CSS и дополнительные параметры", + "settings_nav_desc_notifications": "Оповещения и напоминания", + "settings_nav_desc_units": "Единицы измерения", + "settings_nav_desc_features": "Настройка функций", + "settings_reset_defaults": "Сбросить к значениям по умолчанию", + "settings_cancel_button": "Отмена", + "settings_secure_note": "Ваши настройки хранятся надёжно и применяются на всех устройствах.", + "settings_error_fix_errors": "Исправьте следующие ошибки:", + "settings_fuel_types_label": "Типы топлива", + "settings_fuel_types_desc": "Выберите единицу измерения для каждого вида топлива.", + "fuel_type_label_petrol_diesel": "Бензин / дизель", + "fuel_type_label_lpg": "Пропан (LPG)", + "fuel_type_label_cng": "Метан (CNG)", + "notif_scheduled_delivery": "Отправка по расписанию", + "notif_scheduled_delivery_desc": "Уведомления в приложении приходят сразу. Это расписание влияет только на отправку через провайдеров.", + "notif_processing_schedule": "Расписание обработки", + "notif_processing_schedule_desc": "Отправлять уведомления через провайдеров по расписанию.", + "notif_send_now": "Отправить сейчас", + "notif_providers": "Провайдеры", + "notif_providers_desc": "Создавайте, изменяйте, проверяйте и включайте провайдеров уведомлений.", + "notif_providers_channels_info": "Каждого провайдера можно подписать на каналы «Напоминание», «Оповещение» и «Информация».", + "notif_add_provider": "Добавить провайдера", + "notif_empty_title": "Провайдеры уведомлений пока не настроены", + "notif_empty_desc": "Добавьте провайдера, чтобы получать напоминания, оповещения и информационные уведомления по расписанию.", + "notif_load_failed": "Не удалось загрузить провайдеров уведомлений", + "notif_select_provider_type": "Выберите тип провайдера", + "notif_select_channel": "Выберите хотя бы один канал уведомлений", + "notif_provider_updated": "Провайдер успешно обновлён", + "notif_provider_created": "Провайдер успешно создан", + "notif_provider_deleted": "Провайдер удалён", + "notif_provider_delete_failed": "Не удалось удалить провайдера", + "notif_channel_reminder": "Напоминание", + "notif_channel_reminder_desc": "Сроки и уведомления-напоминания", + "notif_channel_alert": "Оповещение", + "notif_channel_alert_desc": "Срочное или истекающее — требует внимания", + "notif_channel_information": "Информация", + "notif_channel_information_desc": "Общие информационные сообщения", + "notif_provider_enabled": "Включён", + "notif_provider_test": "Проверить провайдера", + "notif_provider_edit": "Изменить провайдера", + "notif_provider_delete": "Удалить провайдера", + "notif_dialog_add_title": "Добавить провайдера уведомлений", + "notif_dialog_edit_title": "Изменить провайдера уведомлений", + "notif_dialog_desc": "Выберите тип провайдера, укажите получателя и подпишите его на нужные каналы. Новые провайдеры включены по умолчанию, отключить их можно на карточке провайдера.", + "notif_provider_name": "Название провайдера", + "notif_provider_name_placeholder": "Ежедневная сводка на email", + "notif_provider_type": "Тип провайдера", + "notif_provider_type_email": "Email (SMTP)", + "notif_provider_type_webhook": "Вебхук", + "notif_provider_type_gotify": "Gotify", + "notif_provider_type_select": "Выберите тип провайдера", + "notif_dialog_cancel": "Отмена", + "notif_dialog_create": "Создать провайдера", + "notif_dialog_update": "Сохранить провайдера", + "notif_channel_subscriptions": "Подписки на каналы", + "notif_channel_subscriptions_desc": "Выберите, какие каналы уведомлений должен получать этот провайдер.", + "notif_test_title": "Проверка провайдера", + "notif_test_success": "Тестовое уведомление успешно отправлено", + "notif_test_email_label": "Тестовый email", + "notif_test_email_placeholder": "recipient@example.com", + "notif_test_email_desc": "Необязательный адрес получателя для этого тестового сообщения.", + "notif_test_message_label": "Тестовое сообщение", + "notif_test_message_placeholder": "Это тестовое уведомление из Tracktor", + "notif_test_send": "Отправить тест", + "notif_cron_presets": "Готовые варианты", + "notif_cron_every_minute": "Каждую минуту", + "notif_cron_every_5_min": "Каждые 5 минут", + "notif_cron_every_15_min": "Каждые 15 минут", + "notif_cron_every_30_min": "Каждые 30 минут", + "notif_cron_every_hour": "Каждый час", + "notif_cron_every_2_hours": "Каждые 2 часа", + "notif_cron_every_6_hours": "Каждые 6 часов", + "notif_cron_every_12_hours": "Каждые 12 часов", + "notif_cron_daily_midnight": "Ежедневно в полночь", + "notif_cron_daily_2am": "Ежедневно в 2:00", + "notif_cron_daily_8am": "Ежедневно в 8:00", + "notif_cron_daily_noon": "Ежедневно в полдень", + "notif_cron_weekly_monday": "Раз в неделю (по понедельникам)", + "notif_cron_monthly_1st": "Раз в месяц (1-го числа)", + "notif_cron_expression_required": "Укажите выражение", + "notif_cron_must_have_5_parts": "Должно быть 5 частей", + "notif_cron_invalid_chars": "Недопустимые символы", + "notif_cron_valid": "Выражение корректно", + "notif_cron_invalid": "Некорректное выражение", + "notif_cron_custom": "Своё расписание", + "notif_email_smtp_settings": "Настройки SMTP-сервера", + "notif_email_host": "Хост", + "notif_email_port": "Порт", + "notif_email_use_ssl": "Использовать SSL/TLS", + "notif_email_use_ssl_desc": "Включить защищённое соединение", + "notif_email_auth": "Аутентификация", + "notif_email_username": "Имя пользователя / email", + "notif_email_password": "Пароль", + "notif_email_password_keep": "Пароль (оставьте пустым, чтобы не менять)", + "notif_email_sender_info": "Отправитель и получатель", + "notif_email_from": "Email отправителя", + "notif_email_from_name": "Имя отправителя (необязательно)", + "notif_email_from_name_placeholder": "Уведомления Tracktor", + "notif_email_recipient": "Email получателя", + "notif_email_recipient_desc": "Адрес электронной почты получателя", + "notif_webhook_config": "Настройка вебхука", + "notif_webhook_url": "URL вебхука", + "notif_webhook_method": "HTTP-метод", + "notif_webhook_headers": "Дополнительные заголовки (JSON)", + "notif_webhook_headers_desc": "Заголовки, которые нужно добавить к запросу вебхука", + "notif_webhook_auth_type": "Тип авторизации", + "notif_webhook_auth_none": "Без авторизации", + "notif_webhook_auth_basic": "Basic Auth", + "notif_webhook_auth_bearer": "Bearer-токен", + "notif_webhook_auth_apikey": "API-ключ", + "notif_webhook_username": "Имя пользователя", + "notif_webhook_apikey_header": "Название заголовка для API-ключа", + "notif_gotify_config": "Настройка сервера Gotify", + "notif_gotify_url": "URL сервера", + "notif_gotify_url_desc": "Адрес вашего сервера Gotify", + "notif_gotify_token": "Токен приложения", + "notif_gotify_token_keep": "Токен приложения (оставьте пустым, чтобы не менять)", + "notif_gotify_token_desc": "Токен приложения из Gotify (не клиентский токен)", + "notif_gotify_priority": "Приоритет (0–10)", + "notif_gotify_priority_desc": "Уровень приоритета сообщения. Чем выше, тем заметнее уведомление", + "notif_cleared_success_one": "Удалено 1 прочитанное уведомление", + "notif_cleared_success_other": "Удалено прочитанных уведомлений: {count}", + "notif_cleared_partial": "Удалено: {success}, с ошибкой: {failed}", + "notif_clear_failed": "Не удалось удалить прочитанные уведомления", + "notif_all_marked_read": "Все уведомления отмечены как прочитанные", + "notif_mark_read_failed": "Не удалось отметить уведомления как прочитанные", + "notif_button_mark_all_read": "Прочитать все", + "notif_button_clear_read": "Удалить прочитанные", + "notif_button_clear_all_read_title": "Удалить все прочитанные уведомления", + "notif_status_read": "Прочитано", + "notif_status_unread": "Не прочитано", + "notif_due_prefix": "Срок: {date}", + "notif_save_provider_failed": "Не удалось сохранить провайдера", + "notif_update_provider_failed": "Не удалось обновить провайдера", + "notif_send_all_failed": "Не удалось отправить уведомления", + "notif_send_all_success": "Отправлено уведомлений: {notifCount} через {successCount}/{providerCount} включённых провайдеров", + "notif_confirm_delete": "Удалить «{name}»?", + "notif_webhook_bearer_keep": "Bearer-токен (оставьте пустым, чтобы не менять)", + "notif_webhook_apikey_keep": "API-ключ (оставьте пустым, чтобы не менять)", + "notif_test_failed": "Не удалось отправить тестовое уведомление", + "notif_test_send_desc": "Отправить тестовое уведомление через «{name}»", + "notif_cron_every_n_minutes": "Каждые {n} минут", + "notif_cron_hourly_at_minute": "Каждый час в {n} минут", + "notif_cron_daily_at": "Ежедневно в {time}", + "vehicle_hub_back_to_vehicles": "К списку автомобилей", + "vehicle_hub_plate_copied": "Госномер скопирован", + "vehicle_hub_insurance_valid_till": "Страховка действует до", + "vehicle_hub_vehicle_type": "Тип транспорта", + "vehicle_hub_activity_title": "Последние события", + "vehicle_hub_activity_empty": "Недавних событий нет", + "vehicle_hub_activity_fuel_added": "Заправка", + "vehicle_hub_activity_maintenance": "Обслуживание", + "vehicle_hub_records_count": "Записей: {count}", + "vehicle_hub_valid_till": "Действует до {date}", + "vehicle_hub_upcoming_count": "Предстоит: {count}", + "vehicle_hub_view_details": "Подробнее", + "vehicle_hub_manage_title": "Управление автомобилем", + "vehicle_hub_stat_odometer": "Одометр", + "vehicle_hub_stat_mileage": "Средний расход", + "vehicle_hub_stat_fuel_logs": "Заправки", + "vehicle_hub_stat_maintenance_logs": "Записи об обслуживании", + "col_vehicle": "Автомобиль", + "overview_chart_pick_vehicle": "Выберите автомобиль, чтобы увидеть этот график", + "fuel_page_title": "Учёт топлива", + "fuel_page_description": "Следите за расходом топлива и затратами", + "fuel_stat_used": "Израсходовано топлива", + "fuel_stat_spent": "Всего потрачено", + "fuel_stat_avg_mileage": "Средний расход", + "fuel_stat_entries": "Всего записей", + "maintenance_page_title": "Обслуживание", + "maintenance_page_description": "История работ и предстоящее обслуживание", + "maintenance_stat_last_service": "Последнее обслуживание", + "maintenance_stat_next_service": "Следующее обслуживание", + "maintenance_stat_odometer": "Одометр", + "maintenance_stat_total_services": "Всего работ", + "maintenance_stat_total_spent": "Всего потрачено", + "maintenance_stat_due_soon": "Скоро срок", + "maintenance_tab_overview": "Обзор", + "maintenance_tab_history": "История обслуживания", + "maintenance_timeline_title": "Хронология обслуживания", + "maintenance_upcoming_empty": "Ничего не запланировано", + "maintenance_history_empty": "История обслуживания пока пуста", + "maintenance_next_service_fallback": "Плановое обслуживание", + "maintenance_also_upcoming": "Также предстоит", + "reminder_page_title": "Напоминания", + "reminder_page_description": "Не пропускайте сроки обслуживания, страховки и техосмотра", + "reminder_filter_all": "Все", + "reminder_filter_all_types": "Все типы", + "reminder_filter_service": "Обслуживание", + "reminder_filter_puc": "Экология", + "reminder_filter_insurance": "Страховка", + "reminder_filter_others": "Прочее", + "reminder_section_upcoming": "Предстоящие", + "reminder_section_completed": "Выполненные", + "reminder_section_marked_done": "Отмечены выполненными", + "reminder_empty_title": "Напоминания пока не настроены", + "reminder_stat_overdue": "Просрочено", + "reminder_stat_due_soon": "Скоро срок", + "reminder_stat_upcoming": "Предстоящие", + "reminder_stat_completed": "Выполнено", + "reminder_calendar_title": "Календарь", + "reminder_quick_actions_title": "Быстрые действия", + "reminder_manage_all_action": "Все напоминания", + "reminder_list_title": "Напоминания", + "reminder_list_title_for_date": "Напоминания на {date}", + "reminder_clear_filter": "Сбросить", + "reminder_calendar_empty_day": "На эту дату напоминаний нет.", + "reports_page_title": "Отчёты", + "reports_page_description": "Расходы и экспорт данных по вашему автопарку", + "reports_section_costs": "Расходы", + "reports_section_details": "Подробный отчёт", + "reports_section_exports": "Экспорт", + "reports_stat_fuel_costs": "Расходы на топливо", + "reports_stat_maintenance_costs": "Расходы на обслуживание", + "reports_chart_breakdown_title": "Структура расходов", + "reports_chart_trend_title": "Расходы по месяцам", + "reports_chart_trend_unavailable": "Динамика по месяцам доступна только для всех автомобилей вместе", + "reports_export_maintenance_title": "История обслуживания", + "reports_export_maintenance_description": "Экспорт истории обслуживания в PDF", + "reports_export_maintenance_hint": "Выберите автомобиль, чтобы экспортировать его историю обслуживания", + "reports_export_data_title": "Полный экспорт данных", + "reports_export_data_description": "Экспорт всех данных автопарка в JSON", + "reports_type_fuel": "Топливо", + "reports_type_maintenance": "Обслуживание", + "reports_type_compliance": "Документы", + "nav_compliance": "Документы", + "vehicle_action_add_compliance": "Добавить документ", + "feature_compliance_disabled_title": "Раздел «Документы» отключён", + "feature_compliance_disabled_hint": "Включите эту функцию в настройках, чтобы вести страховку, экологический контроль, техосмотр и регистрацию", + "feature_label_compliance": "Документы", + "feature_desc_compliance": "Учёт страховки, экологического контроля, техосмотра и регистрации", + "compliance_type_insurance": "Страховка", + "compliance_type_emissions": "Экологический контроль", + "compliance_type_roadworthiness": "Техосмотр", + "compliance_type_registration": "Регистрация / транспортный налог", + "compliance_type_other": "Другое", + "compliance_field_policy_number": "Номер полиса", + "compliance_field_certificate_number": "Номер сертификата", + "compliance_field_registration_number": "Регистрационный номер", + "compliance_field_document_number": "Номер документа", + "compliance_field_provider": "Страховая компания", + "compliance_field_testing_center": "Пункт контроля", + "compliance_field_inspection_center": "Пункт техосмотра", + "compliance_field_issuing_authority": "Кем выдан", + "compliance_recurrence_type_fixed": "Фиксированная дата окончания", + "compliance_recurrence_type_yearly": "Продлевается ежегодно", + "compliance_recurrence_type_monthly": "Продлевается ежемесячно", + "compliance_recurrence_type_no_end": "Без даты окончания", + "compliance_form_type_label": "Тип документа", + "compliance_form_type_desc": "Какой это документ", + "compliance_form_other_label_label": "Название типа", + "compliance_form_other_label_desc": "Назовите этот тип документа, например «WOF (Новая Зеландия)» или «TÜV (Германия)»", + "compliance_form_attachment_label": "Документ", + "compliance_form_attachment_desc": "Загрузите документ", + "compliance_form_issuer_desc": "Компания, пункт контроля или орган, выдавший документ", + "compliance_form_document_number_desc": "Номер, указанный в документе", + "compliance_form_start_date_label": "Дата начала", + "compliance_form_start_date_desc": "Дата, с которой документ действует", + "compliance_form_recurrence_type_label": "Как продлевается документ?", + "compliance_form_recurrence_type_desc": "Тип продления для этого документа", + "compliance_form_recurrence_interval_desc": "Как часто документ продлевается", + "compliance_form_end_date_label": "Дата окончания", + "compliance_form_end_date_desc": "Дата, когда документ перестаёт действовать", + "compliance_form_cost_label": "Стоимость", + "compliance_form_cost_desc": "Стоимость документа, если есть", + "compliance_form_notes_label": "Дополнительные заметки", + "compliance_form_notes_desc": "Любая дополнительная информация", + "compliance_form_notes_placeholder": "Добавьте подробности…", + "compliance_form_error_fix": "Исправьте ошибки в форме перед отправкой.", + "compliance_toast_saved": "Документ успешно сохранён", + "compliance_toast_updated": "Документ успешно обновлён", + "compliance_toast_error_prefix": "Ошибка при сохранении: ", + "compliance_list_empty": "Для этого автомобиля документы не найдены.", + "compliance_col_cost": "Стоимость", + "compliance_col_start_date": "Дата начала", + "compliance_col_end_date": "Дата окончания", + "compliance_col_next_due": "Следующий срок", + "compliance_col_recurrence": "Продление", + "compliance_col_notes": "Заметки", + "compliance_col_view_document": "Открыть документ", + "compliance_menu_open": "Открыть меню", + "compliance_menu_edit": "Изменить", + "compliance_menu_delete": "Удалить", + "compliance_menu_sheet_title": "Изменить документ", + "compliance_delete_success": "Документ удалён.", + "compliance_delete_error": "При удалении документа произошла ошибка.", + "compliance_page_title": "Документы", + "compliance_page_description": "Контроль страховки, экологического контроля, техосмотра и регистрации", + "compliance_add_action": "Добавить документ", + "compliance_filter_all_types": "Все типы", + "compliance_filter_all": "Все", + "compliance_filter_valid": "Действующие", + "compliance_filter_expiring_soon": "Скоро истекают", + "compliance_filter_expired": "Истёкшие", + "compliance_stat_total": "Всего", + "compliance_stat_valid": "Действующие", + "compliance_stat_expiring_soon": "Скоро истекают", + "compliance_stat_expired": "Истёкшие", + "compliance_cta_heading": "Держите документы в порядке", + "compliance_cta_description": "Обновляйте документы вовремя, чтобы избежать штрафов и законно ездить.", + "vehicle_hub_other_compliance_valid_till": "Другие документы действуют до", + "vehicle_hub_activity_compliance_updated": "Документ обновлён", + "vehicle_hub_activity_document_prefix": "Документ №", + "reports_stat_compliance_costs": "Расходы на документы", + "compliance_col_document": "Документ", + "compliance_col_status": "Статус", + "compliance_col_days_left": "Осталось дней" +} diff --git a/i18n/project.inlang/settings.json b/i18n/project.inlang/settings.json index aed47185..5dec532c 100644 --- a/i18n/project.inlang/settings.json +++ b/i18n/project.inlang/settings.json @@ -8,5 +8,5 @@ "pathPattern": "./messages/{locale}.json" }, "baseLocale": "en", - "locales": ["en", "ar", "hi", "es", "fr", "de", "it", "hu", "fi", "ro"] + "locales": ["en", "ar", "hi", "es", "fr", "de", "it", "hu", "fi", "ro", "ru"] } diff --git a/src/lib/helper/settings-form.helper.ts b/src/lib/helper/settings-form.helper.ts index 194d1ae6..5a3884ba 100644 --- a/src/lib/helper/settings-form.helper.ts +++ b/src/lib/helper/settings-form.helper.ts @@ -77,7 +77,8 @@ export function createSettingsOptions( it: 'Italiano', hu: 'Magyar', fi: 'Suomi', - ro: 'Română' + ro: 'Română', + ru: 'Русский' }; return { From f2974dde4005bd56def54fcd3511388b6f7c3d5c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 11 Aug 2026 22:19:51 +0000 Subject: [PATCH 7/9] Add European Portuguese (pt-PT) translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add i18n/messages/pt-PT.json with all 811 messages translated, reviewed by a native speaker - Register pt-PT in the inlang project locales - Add 'Português (Portugal)' label to the locale dropdown Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01YXazaegVWZdeKziwMzPKPG --- i18n/messages/pt-PT.json | 813 +++++++++++++++++++++++++ i18n/project.inlang/settings.json | 2 +- src/lib/helper/settings-form.helper.ts | 3 +- 3 files changed, 816 insertions(+), 2 deletions(-) create mode 100644 i18n/messages/pt-PT.json diff --git a/i18n/messages/pt-PT.json b/i18n/messages/pt-PT.json new file mode 100644 index 00000000..ccfbd998 --- /dev/null +++ b/i18n/messages/pt-PT.json @@ -0,0 +1,813 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "hello_world": "Olá, {name} de pt-PT!", + "app_name": "Tracktor", + "app_title": "A sua garagem", + "app_new_update_available": "Uma nova atualização está disponível. A recarregar…", + "app_add_vehicle": "Adicionar veículo", + "vehicle_scope_all": "Todos os veículos", + "vehicle_scope_manage": "Gerir veículos", + "form_vehicle_label": "Veículo", + "form_vehicle_desc": "A que veículo pertence este registo", + "app_empty_select_message": "Selecione um veículo para ver os detalhes", + "app_empty_select_hint": "Escolha um veículo na garagem acima para carregar o respetivo painel.", + "demo_banner": "Esta é uma instância de demonstração. Os dados são repostos periodicamente e não são guardados de forma permanente. Evite introduzir informação pessoal.", + "default_login": "Credenciais predefinidas: demo / demo", + "auth_username": "Nome de utilizador", + "auth_username_placeholder": "nome de utilizador", + "auth_password": "Palavra-passe", + "auth_password_placeholder": "********", + "auth_confirm_password": "Confirmar palavra-passe", + "auth_login_button": "Iniciar sessão", + "auth_signup_button": "Criar conta", + "auth_login_loading": "A iniciar sessão...", + "auth_signup_loading": "A criar conta...", + "auth_password_mismatch": "As palavras-passe não coincidem!", + "auth_login_title": "Bem-vindo de volta", + "auth_login_subtitle": "Inicie sessão para manter os seus veículos, abastecimentos e documentos em dia.", + "settings_tab_personalization": "Personalização", + "settings_tab_interface": "Interface", + "settings_tab_localization": "Localização", + "settings_tab_advanced": "Avançadas", + "settings_tab_features": "Funcionalidades", + "settings_tab_units": "Unidades", + "settings_title": "Definições", + "settings_page_description": "Configure a aparência, o idioma, os formatos regionais e o comportamento da interface.", + "settings_label_date_format": "Formato de data", + "settings_label_locale": "Idioma", + "settings_label_timezone": "Fuso horário", + "settings_label_currency": "Moeda", + "settings_label_unit_distance": "Unidade de distância", + "settings_label_unit_volume": "Unidade de combustível", + "settings_label_theme": "Tema", + "settings_label_dark_mode": "Estilo do modo escuro", + "settings_label_custom_css": "CSS personalizado", + "settings_update_button": "Atualizar definições", + "settings_select_unit_system": "Selecionar sistema de unidades", + "settings_select_theme": "Selecionar tema", + "settings_select_dark_mode": "Selecionar estilo do modo escuro", + "settings_desc_date_format": "Indique o formato de data da sua preferência", + "settings_desc_locale": "Escolha o idioma da interface", + "settings_desc_timezone": "Escolha o fuso horário para a apresentação de datas", + "settings_desc_currency": "Escolha a moeda da sua preferência", + "settings_desc_unit_distance": "Unidade de medida de distância", + "settings_desc_unit_volume": "Unidade de medida de volume", + "settings_label_mileage_format": "Formato de apresentação do consumo", + "settings_desc_mileage_format": "Escolha como o consumo de combustível é apresentado", + "settings_mileage_format_distance_per_fuel": "Distância por volume de combustível (ex.: km/L, mpg)", + "settings_mileage_format_fuel_per_distance": "Volume de combustível por distância (ex.: L/100km)", + "settings_mileage_format_uk_mpg": "MPG britânico (milhas por galão imperial)", + "settings_desc_theme": "Escolha o tema da sua preferência", + "settings_desc_dark_mode": "Escolha o estilo de contraste usado quando o modo escuro está ativo", + "settings_desc_custom_css": "Estilos CSS para personalizar a interface", + "settings_select_language": "Selecionar idioma", + "settings_updated_success": "Definições atualizadas com sucesso!", + "common_example_prefix": "Exemplo: ", + "common_invalid_format": "Formato inválido...", + "common_kilometer": "Quilómetro", + "common_mile": "Milha", + "common_litre": "Litro", + "common_gallon": "Galão", + "common_submit": "Submeter", + "common_details": "Detalhes", + "common_close": "Fechar", + "common_view": "Ver", + "common_view_all": "Ver tudo", + "common_view_less": "Mostrar menos", + "common_loading": "A carregar...", + "common_add": "Adicionar", + "common_yes": "Sim", + "common_no": "Não", + "common_cancel": "Cancelar", + "common_confirm": "Confirmar", + "common_continue": "Continuar", + "common_skip": "Ignorar", + "delete_dialog_title": "Eliminar", + "delete_dialog_message": "Tem a certeza de que pretende eliminar?", + "common_select_column": "Selecionar coluna", + "common_import": "Importar", + "common_search": "Pesquisar", + "common_columns": "Colunas", + "common_rows_per_page": "Linhas por página", + "common_no_data_available": "Sem dados disponíveis", + "common_no_records_found": "Não foram encontrados registos", + "common_add_new": "Adicionar novo", + "common_no_match_found": "Nenhum resultado encontrado", + "common_search_placeholder": "Pesquisar {name}", + "common_select_placeholder": "Selecionar {name}...", + "common_date_from": "De", + "common_date_to": "Até", + "common_export_csv": "Exportar CSV", + "nav_overview": "Visão geral", + "nav_fuel_logs": "Abastecimentos", + "nav_maintenance": "Manutenção", + "nav_reminders": "Lembretes", + "tools_export_data": "Exportar dados", + "tools_import_data": "Importar dados", + "vehicle_form_make_label": "Marca", + "vehicle_form_make_desc": "Fabricante do veículo", + "vehicle_form_model_label": "Modelo", + "vehicle_form_model_desc": "Modelo do veículo", + "vehicle_form_year_label": "Ano", + "vehicle_form_year_desc": "Ano de fabrico", + "vehicle_form_color_label": "Cor", + "vehicle_form_color_desc": "Cor do veículo", + "vehicle_form_fuel_type_label": "Tipo de combustível", + "vehicle_form_fuel_type_desc": "Tipo de combustível utilizado pelo veículo", + "vehicle_form_fuel_type_placeholder": "Selecionar tipo de combustível", + "vehicle_form_vehicle_type_label": "Tipo de veículo", + "vehicle_form_vehicle_type_desc": "Categoria do veículo", + "vehicle_form_vehicle_type_placeholder": "Selecionar tipo de veículo", + "vehicle_form_odometer_label": "Conta-quilómetros", + "vehicle_form_odometer_desc": "Leitura atual do conta-quilómetros", + "vehicle_form_license_label": "Matrícula", + "vehicle_form_license_desc": "Número de matrícula do veículo", + "vehicle_form_vin_label": "VIN", + "vehicle_form_vin_desc": "Número de identificação do veículo (VIN)", + "vehicle_toast_saved": "Veículo guardado com sucesso", + "vehicle_toast_updated": "Veículo atualizado com sucesso", + "vehicle_toast_error_prefix": "Erro ao guardar: ", + "vehicle_list_empty": "Está vazio por aqui. Adicione o seu primeiro veículo para começar.", + "vehicle_delete_success": "Veículo eliminado com sucesso.", + "vehicle_delete_error": "Ocorreu um erro ao eliminar o veículo.", + "vehicle_action_add_fuel_log": "Adicionar abastecimento", + "vehicle_action_add_maintenance_log": "Adicionar registo de manutenção", + "vehicle_action_add_reminder": "Adicionar lembrete", + "vehicle_action_more_info": "Mais informações", + "vehicle_action_update_vehicle": "Atualizar veículo", + "vehicle_action_edit": "Editar", + "vehicle_action_delete": "Eliminar", + "tools_export_encrypt_label": "Encriptar dados exportados", + "tools_export_password_label": "Palavra-passe de encriptação", + "tools_export_password_placeholder": "Introduza a palavra-passe para encriptação", + "tools_export_password_hint": "Guarde esta palavra-passe em segurança — vai precisar dela para desencriptar os dados durante a importação.", + "tools_export_status_exporting": "A exportar...", + "tools_export_button": "Exportar base de dados", + "tools_export_info_title": "Informação da exportação", + "tools_export_info_bullet_1": "Exporta todas as tabelas e dados da base de dados", + "tools_export_info_bullet_2": "Inclui veículos, abastecimentos, registos de manutenção, etc.", + "tools_export_info_bullet_3": "Encriptação opcional para proteção de dados sensíveis", + "tools_export_info_bullet_4": "Exporta como um ficheiro JSON", + "tools_export_success": "Dados exportados com sucesso", + "tools_export_error": "Falha ao exportar os dados", + "tools_import_upload_label": "Carregar ficheiro JSON", + "tools_import_paste_label": "Ou colar dados JSON", + "tools_import_paste_placeholder": "Cole aqui os dados JSON exportados...", + "tools_import_password_label": "Palavra-passe de desencriptação (se encriptado)", + "tools_import_password_placeholder": "Introduza a palavra-passe se os dados estiverem encriptados", + "tools_import_status_importing": "A importar...", + "tools_import_button": "Importar base de dados", + "tools_import_warning_title": "⚠️ Aviso de importação", + "tools_import_warning_bullet_1": "Esta operação substitui TODOS os dados existentes", + "tools_import_warning_bullet_2": "Faça primeiro uma cópia de segurança dos dados atuais", + "tools_import_warning_bullet_3": "A importação não pode ser anulada", + "tools_import_warning_bullet_4": "Verifique se o formato JSON está correto", + "tools_import_success": "Dados importados com sucesso", + "tools_import_error": "Falha ao importar os dados", + "tools_import_invalid_json": "Formato JSON inválido", + "feature_overview_disabled_title": "Funcionalidade de visão geral desativada", + "feature_overview_disabled_hint": "Ative esta funcionalidade nas Definições para ver o painel de visão geral", + "feature_fuel_disabled_title": "Funcionalidade de abastecimentos desativada", + "feature_fuel_disabled_hint": "Ative esta funcionalidade nas Definições para acompanhar o consumo de combustível", + "feature_maintenance_disabled_title": "Funcionalidade de manutenção desativada", + "feature_maintenance_disabled_hint": "Ative esta funcionalidade nas Definições para gerir registos de manutenção", + "feature_reminders_disabled_title": "Funcionalidade de lembretes desativada", + "feature_reminders_disabled_hint": "Ative esta funcionalidade nas Definições para gerir lembretes do veículo", + "overview_chart_no_data": "Sem dados disponíveis", + "overview_chart_cost_label": "Custo", + "overview_chart_cost_title": "Custo ao longo do tempo ({currency})", + "overview_chart_mileage_label": "Consumo", + "overview_chart_mileage_title": "Consumo ao longo do tempo ({unit})", + "fuel_import_title": "Importar abastecimentos", + "fuel_add_title": "Adicionar abastecimento", + "col_date": "Data", + "col_odometer": "Conta-quilómetros", + "col_distance_driven": "Distância percorrida", + "col_filled": "Atestado", + "col_missed_last": "Falhou o anterior", + "col_fuel_amount": "Quantidade de combustível", + "col_cost": "Custo", + "col_mileage": "Consumo", + "col_notes": "Notas", + "col_attachment": "Anexo", + "col_no_end_date": "Sem data de fim", + "fuel_volume_label_fuel": "Quantidade de combustível", + "fuel_volume_label_energy": "Energia", + "fuel_empty_list": "Não foram encontrados abastecimentos para este veículo.", + "form_date": "Data", + "form_date_desc": "Data do abastecimento", + "form_odometer": "Conta-quilómetros", + "form_odometer_desc": "Leitura atual do conta-quilómetros", + "form_volume_fuel": "Volume de combustível", + "form_volume_energy": "Energia consumida", + "form_rate": "Preço unitário", + "form_cost": "Custo", + "form_cost_desc": "Custo do abastecimento", + "form_cost_desc_ev": "Custo do carregamento", + "form_full_charge": "Carga completa", + "form_full_tank": "Depósito cheio", + "form_full_charge_desc": "A bateria ficou totalmente carregada?", + "form_full_tank_desc": "O depósito ficou atestado?", + "form_missed_last": "Falhou o anterior", + "form_missed_last_desc": "Ficou algum abastecimento anterior por registar?", + "form_notes": "Notas", + "form_notes_placeholder": "Adicione mais detalhes, se necessário...", + "form_attachment": "Anexo", + "fuel_toast_saved": "Abastecimento guardado com sucesso!", + "fuel_toast_updated": "Abastecimento atualizado com sucesso!", + "fuel_toast_error_prefix": "Erro ao guardar: ", + "notifications_title": "Notificações", + "notifications_new": "novas", + "notifications_syncing": "A sincronizar os dados mais recentes...", + "notifications_caught_up": "Está tudo em dia.", + "notifications_section_reminders": "Lembretes", + "notifications_section_alerts": "Alertas de conformidade", + "notifications_mark_done_title": "Marcar lembrete como concluído", + "notifications_mark_done_aria": "Marcar lembrete de {type} como concluído", + "notifications_mark_all_read_title": "Marcar tudo como lido", + "notifications_mark_all_read_aria": "Marcar todas as notificações como lidas", + "notifications_overdue_days": "{days} dia{plural} em atraso", + "notifications_due_today": "Vence hoje", + "notifications_due_tomorrow": "Vence amanhã", + "notifications_due_in_days": "Vence dentro de {days} dias", + "alerts_status_expired": "Expirado", + "alerts_status_expiring": "A expirar", + "alerts_status_valid": "Válido", + "alerts_status_missing": "Em falta", + "notifications_expires": "Expira", + "notifications_error_no_id": "Não é possível atualizar um lembrete sem ID.", + "notifications_error_update_failed": "Falha ao atualizar o lembrete.", + "notifications_success_marked_done": "Lembrete marcado como concluído.", + "notifications_severity_overdue": "Em atraso", + "notifications_severity_due_soon": "Vence em breve", + "notifications_severity_upcoming": "Próximo", + "settings_custom_css_placeholder": "Adicione aqui o seu CSS personalizado...", + "settings_features_intro": "Ative ou desative funcionalidades para personalizar a sua experiência", + "feature_label_fuel": "Abastecimentos", + "feature_desc_fuel": "Acompanhe e faça a gestão do consumo de combustível e do histórico de abastecimentos", + "feature_label_maintenance": "Manutenção", + "feature_desc_maintenance": "Registe e agende atividades de manutenção do veículo", + "feature_label_reminders": "Lembretes", + "feature_desc_reminders": "Defina e receba lembretes para eventos importantes do veículo", + "feature_label_overview": "Visão geral", + "feature_desc_overview": "Apresenta um painel com as principais métricas do veículo", + "settings_error_date_format_invalid": "Formato inválido", + "settings_error_timezone_invalid": "Fuso horário inválido", + "settings_error_currency_required": "A moeda é obrigatória", + "maintenance_form_attachment_label": "Anexo", + "maintenance_form_attachment_desc": "Carregue a fatura ou documento da manutenção", + "maintenance_form_date_label": "Data", + "maintenance_form_date_desc": "Data da manutenção", + "maintenance_form_odometer_label": "Conta-quilómetros", + "maintenance_form_odometer_desc": "Leitura atual do conta-quilómetros", + "maintenance_form_service_center_label": "Oficina", + "maintenance_form_service_center_desc": "Nome da oficina", + "maintenance_form_cost_label": "Custo", + "maintenance_form_cost_desc": "Custo da manutenção", + "maintenance_form_notes_label": "Notas", + "maintenance_form_notes_desc": "Mais detalhes", + "maintenance_form_notes_placeholder": "Adicione mais detalhes, se necessário...", + "maintenance_toast_saved": "Registo de manutenção guardado com sucesso", + "maintenance_toast_updated": "Registo de manutenção atualizado com sucesso", + "maintenance_toast_error_prefix": "Erro ao guardar: ", + "maintenance_form_error_fix": "Corrija os erros do formulário antes de submeter.", + "maintenance_list_empty": "Não foram encontrados registos de manutenção para este veículo.", + "maintenance_col_service_center": "Oficina", + "maintenance_menu_open": "Abrir menu", + "maintenance_menu_edit": "Editar", + "maintenance_menu_delete": "Eliminar", + "maintenance_menu_sheet_title": "Atualizar registo de manutenção", + "maintenance_tab_title": "Histórico de manutenção", + "maintenance_add_action": "Adicionar registo de manutenção", + "maintenance_export_pdf": "Exportar PDF", + "maintenance_delete_success": "Registo de manutenção eliminado.", + "maintenance_delete_error": "Ocorreu um erro ao eliminar o registo de manutenção.", + "reminder_form_due_date_label": "Data-limite", + "reminder_form_due_date_desc": "Quando deve este lembrete disparar?", + "reminder_form_type_label": "Tipo", + "reminder_form_type_desc": "Escolha o tipo de lembrete", + "reminder_form_schedule_label": "Antecedência do lembrete", + "reminder_form_schedule_desc": "Quando devemos lembrá-lo?", + "reminder_form_recurrence_type_label": "Recorrência", + "reminder_form_recurrence_type_desc": "Este lembrete deve repetir-se?", + "reminder_form_recurrence_interval_label": "Repetir a cada", + "reminder_form_recurrence_interval_desc": "Frequência da recorrência", + "reminder_form_recurrence_end_date_label": "Data de fim", + "reminder_form_recurrence_end_date_desc": "Quando deve a recorrência terminar? (opcional)", + "reminder_form_note_label": "Nota", + "reminder_form_note_desc": "Adicione mais contexto", + "reminder_form_note_placeholder": "Descreva o que precisa de atenção", + "reminder_form_is_completed_label": "Marcar como concluído", + "reminder_toast_created": "Lembrete criado com sucesso.", + "reminder_toast_updated": "Lembrete atualizado com sucesso", + "reminder_toast_error_prefix": "Erro ao guardar: ", + "reminder_list_empty": "Ainda não há lembretes. Crie um para se antecipar às próximas renovações.", + "reminder_list_select_vehicle": "Selecione um veículo para ver os lembretes.", + "reminder_list_select_hint": "Escolha um veículo acima para carregar os próximos lembretes.", + "reminder_col_due_date": "Data-limite", + "reminder_col_reminder_schedule": "Antecedência", + "reminder_col_recurrence": "Recorrência", + "reminder_col_note": "Notas", + "reminder_menu_toggle_done": "Marcar como {status}", + "reminder_menu_toggle_done_done": "Marcar como pendente", + "reminder_menu_toggle_done_pending": "Marcar como concluído", + "reminder_menu_edit": "Editar", + "reminder_menu_delete": "Eliminar", + "reminder_menu_open": "Abrir menu", + "reminder_menu_sheet_title": "Atualizar lembrete", + "reminder_add_action": "Adicionar lembrete", + "reminder_delete_success": "Lembrete eliminado.", + "reminder_delete_error": "Ocorreu um erro ao eliminar o lembrete.", + "reminder_status_completed": "Concluído", + "reminder_status_pending": "Pendente", + "reminder_status_overdue": "Em atraso", + "reminder_status_error": "Não foi possível atualizar o estado do lembrete.", + "reminder_toast_error_fallback": "Falha ao guardar o lembrete.", + "settings_sheet_title": "Definições", + "profile_menu_item": "Perfil", + "profile_sheet_title": "Perfil", + "profile_sheet_desc": "Atualize o seu nome de utilizador e palavra-passe", + "profile_username": "Nome de utilizador", + "profile_username_desc": "O seu nome a apresentar", + "profile_password_hint": "Deixe os campos de palavra-passe vazios para manter a palavra-passe atual", + "profile_current_password": "Palavra-passe atual", + "profile_current_password_desc": "Necessária para alterar a palavra-passe", + "profile_new_password": "Nova palavra-passe", + "profile_new_password_desc": "Mínimo de 6 caracteres", + "profile_confirm_password": "Confirmar palavra-passe", + "profile_confirm_password_desc": "Volte a introduzir a nova palavra-passe", + "profile_update_button": "Atualizar perfil", + "tools_menu": "Ferramentas", + "data_export_import_menu_item": "Exportar/importar dados", + "data_export_import_sheet_title": "Exportação/importação de dados", + "data_export_import_sheet_desc": "Exporte ou importe a sua base de dados com encriptação opcional", + "logout_menu_item": "Terminar sessão", + "custom_fields_label": "Campos personalizados", + "custom_fields_add_button": "Adicionar campo", + "custom_fields_name_placeholder": "Nome do campo", + "custom_fields_value_placeholder": "Valor do campo", + "custom_fields_remove_aria": "Remover campo", + "custom_fields_empty_message": "Sem campos personalizados. Clique em \"Adicionar campo\" para começar.", + "vehicle_details_vin": "VIN", + "vehicle_details_not_specified": "Não especificado", + "vehicle_details_not_available": "Não disponível", + "vehicle_details_section_title": "Detalhes", + "vehicle_details_license_plate": "Matrícula", + "vehicle_details_fuel_type": "Tipo de combustível", + "vehicle_details_odometer": "Conta-quilómetros", + "vehicle_details_not_recorded": "Não registado", + "vehicle_details_color": "Cor", + "vehicle_details_year": "Ano", + "vehicle_type_car": "Automóvel", + "vehicle_type_motorcycle": "Mota", + "vehicle_type_scooter": "Scooter", + "vehicle_type_truck": "Camião", + "vehicle_type_van": "Carrinha", + "vehicle_type_bus": "Autocarro", + "vehicle_type_farm_vehicle": "Veículo agrícola", + "vehicle_type_yacht": "Iate", + "vehicle_type_rv": "Autocaravana / caravana", + "vehicle_type_other": "Outro", + "fuel_type_diesel": "Gasóleo", + "fuel_type_petrol": "Gasolina", + "fuel_type_electric": "Elétrico", + "fuel_type_lpg": "GPL", + "fuel_type_cng": "GNC", + "fuel_type_ev": "Elétrico (EV)", + "reminder_schedule_same_day": "Na data-limite", + "reminder_schedule_one_day_before": "1 dia antes", + "reminder_schedule_three_days_before": "3 dias antes", + "reminder_schedule_one_week_before": "1 semana antes", + "reminder_schedule_one_month_before": "1 mês antes", + "recurrence_type_none": "Sem recorrência", + "recurrence_type_daily": "Diária", + "recurrence_type_weekly": "Semanal", + "recurrence_type_monthly": "Mensal", + "recurrence_type_yearly": "Anual", + "recurrence_every": "a cada", + "recurrence_renew_every": "Renova a cada", + "recurrence_interval_days": "dias", + "recurrence_interval_weeks": "semanas", + "recurrence_interval_months": "meses", + "recurrence_interval_years": "anos", + "recurrence_until": "Até", + "file_drop_existing_note": "Anexo existente (clique para ver)", + "fuel_import_step_1_title": "Passo 1: Carregar ficheiro CSV", + "fuel_import_step_1_desc": "Selecione um ficheiro de texto delimitado com os dados dos seus abastecimentos para iniciar a importação.", + "fuel_import_drop_placeholder": "Largue aqui um ficheiro de texto delimitado ou clique para procurar", + "fuel_import_headers_checkbox": "A primeira linha contém cabeçalhos", + "fuel_import_delimiter_title": "Delimitador", + "fuel_import_delimiter_desc": "Escolha o carácter que separa os campos", + "fuel_import_date_format_title": "Formato de data", + "fuel_import_date_format_desc": "Indique o formato usado para as datas no seu ficheiro CSV.", + "fuel_import_error_no_headers": "Não foram detetados cabeçalhos. Atualize csv.helper.ts para devolver cabeçalhos.", + "fuel_import_step_2_title": "Passo 2: Mapear colunas do CSV", + "fuel_import_step_2_desc": "Associe as colunas do seu ficheiro CSV aos campos de abastecimento correspondentes. Os campos obrigatórios estão marcados com *.", + "fuel_import_step_3_title": "Passo 3: Pré-visualizar e importar", + "fuel_import_step_3_desc": "Reveja uma pré-visualização dos dados a importar.", + "fuel_import_no_preview": "Ainda não há dados de pré-visualização. Implemente o parsing em csv.helper.ts para preencher as linhas.", + "fuel_import_success": "{count} abastecimento(s) importado(s) com sucesso.", + "fuel_import_failed_count": "Importados {imported}, falharam {failed}", + "fuel_import_error_generic": "A importação de abastecimentos falhou.", + "fuel_import_vehicle_label": "Veículo:", + "fuel_import_delimiter_comma": "Vírgula ( , )", + "fuel_import_delimiter_semicolon": "Ponto e vírgula ( ; )", + "fuel_import_delimiter_tab": "Tabulação ( \\t )", + "fuel_import_delimiter_pipe": "Barra vertical ( | )", + "fuel_import_delimiter_custom": "Personalizado", + "fuel_import_date_error": "Algumas linhas têm datas inválidas para o formato \"{format}\"", + "fuel_import_date_format_placeholder": "ex.: DD/MM/YYYY", + "fuel_import_date_invalid": "Data inválida", + "fuel_import_no_vehicle": "Nenhum veículo selecionado", + "fuel_import_col_date_hint": "Data do abastecimento", + "fuel_import_col_odometer_hint": "Leitura no momento do abastecimento", + "fuel_import_col_fuel_hint": "Volume ou energia carregada", + "fuel_import_col_cost_hint": "Custo total do registo", + "fuel_import_col_filled_hint": "Foi um depósito cheio/carga completa?", + "fuel_import_col_missed_hint": "O registo anterior ficou em falta?", + "fuel_import_col_notes_hint": "Notas adicionais", + "autocomplete_placeholder": "Escreva ou selecione...", + "autocomplete_loading": "A carregar sugestões...", + "autocomplete_no_results": "Sem sugestões. Pode escrever um novo valor.", + "input_date_placeholder": "Escolha uma data", + "loading_default_message": "A carregar...", + "dropzone_placeholder_image": "Clique ou arraste uma imagem para carregar", + "dropzone_placeholder_attachment": "Largue o ficheiro aqui ou clique para selecionar", + "dropzone_placeholder_default": "Clique ou arraste ficheiros para carregar", + "dropzone_error_single_file": "Carregue apenas um ficheiro.", + "dropzone_error_file_size": "O tamanho do ficheiro excede o limite máximo de {size}.", + "dropzone_unknown_file": "Ficheiro desconhecido", + "dropzone_uploading": "A carregar...", + "dropzone_supports": "Suporta: {types}", + "dropzone_max_size": "Tamanho máximo: {size}", + "dropzone_error_file_type": "Tipo de ficheiro não permitido", + "dropzone_hint_accept_limit": "{types} até {size}", + "vehicle_details_color_aria": "Cor", + "vehicle_details_close_aria": "Fechar", + "attachment_link_view_title": "Ver anexo", + "file_preview_not_available": "Pré-visualização indisponível", + "file_preview_download_hint": "Este tipo de ficheiro não pode ser pré-visualizado diretamente. Transfira-o para o ver.", + "file_preview_download_button": "Transferir ficheiro", + "file_preview_aria_download": "Transferir", + "file_preview_aria_close": "Fechar", + "theme_toggle_label": "Alternar tema", + "fuel_log_edit": "Editar", + "fuel_log_delete": "Eliminar", + "fuel_log_menu_open": "Abrir menu", + "fuel_log_delete_success": "Abastecimento eliminado", + "fuel_log_menu_sheet_title": "Atualizar abastecimento", + "fuel_log_delete_error": "Ocorreu um erro ao eliminar o abastecimento.", + "color_picker_label": "Escolha uma cor", + "reminder_type_maintenance": "Manutenção", + "reminder_type_insurance": "Renovação do seguro", + "reminder_type_pollution": "Emissões / certificado", + "reminder_type_registration": "Registo / imposto", + "reminder_type_inspection": "Inspeção", + "reminder_type_custom": "Personalizado", + "alert_status_expired_ago": "{label} expirou há {days} dias", + "alert_status_expires_in": "{label} expira dentro de {days} dias", + "alert_status_valid_for": "{label} válido por {days} dias", + "alert_record_not_found": "Registo de {label} não encontrado. Adicione os dados para se manter em conformidade.", + "settings_error_format_not_valid": "Formato inválido", + "common_kilogram_unit": "Quilograma (kg)", + "common_pound_unit": "Libra (lb)", + "settings_section_fuel_types": "Tipos de combustível", + "settings_section_fuel_types_desc": "Escolha a unidade de medida para cada combustível.", + "fuel_type_petrol_diesel": "Gasolina/Gasóleo", + "theme_slate": "Ardósia", + "theme_stone": "Pedra", + "theme_red": "Vermelho", + "theme_rose": "Rosa-velho", + "theme_blue": "Azul", + "theme_green": "Verde", + "theme_purple": "Roxo", + "theme_orange": "Laranja", + "theme_yellow": "Amarelo", + "theme_teal": "Azul-petróleo", + "theme_indigo": "Índigo", + "theme_pink": "Rosa", + "dark_variant_default": "Predefinido", + "dark_variant_dim": "Suave", + "dark_variant_oled": "OLED (preto puro)", + "settings_tab_notifications": "Notificações", + "settings_personalization_desc": "Personalize a sua experiência com temas, idiomas e formatos.", + "settings_section_general": "Geral", + "settings_section_general_desc": "Personalize a aparência, a localização e os formatos de apresentação", + "settings_units_desc": "Configure as unidades de medida para distância, volume e tipos de combustível.", + "settings_section_units": "Unidades", + "settings_section_units_desc": "Escolha as unidades da sua preferência para distância, consumo e tipos de combustível", + "settings_section_feature_flags": "Funcionalidades", + "settings_section_feature_flags_desc": "Ative ou desative os principais módulos da aplicação", + "settings_notifications_desc": "Configure as subscrições de fornecedores e a hora diária de processamento para envio agendado.", + "settings_localization_desc": "Defina o idioma e as preferências regionais.", + "settings_advanced_desc": "Afine a interface com estilos personalizados.", + "settings_nav_desc_personalization": "Tema, apresentação e estilo", + "settings_nav_desc_localization": "Idioma e formatos regionais", + "settings_nav_desc_advanced": "CSS personalizado e opções avançadas", + "settings_nav_desc_notifications": "Alertas e lembretes", + "settings_nav_desc_units": "Unidades de medida", + "settings_nav_desc_features": "Preferências de funcionalidades", + "settings_reset_defaults": "Repor predefinições", + "settings_cancel_button": "Cancelar", + "settings_secure_note": "As suas preferências são guardadas de forma segura e aplicadas em todos os seus dispositivos.", + "settings_error_fix_errors": "Corrija os seguintes erros:", + "settings_fuel_types_label": "Tipos de combustível", + "settings_fuel_types_desc": "Escolha a unidade de medida para cada combustível.", + "fuel_type_label_petrol_diesel": "Gasolina/Gasóleo", + "fuel_type_label_lpg": "GPL", + "fuel_type_label_cng": "GNC", + "notif_scheduled_delivery": "Envio agendado", + "notif_scheduled_delivery_desc": "As notificações na aplicação continuam em tempo real. Este agendamento controla apenas o envio pelos fornecedores.", + "notif_processing_schedule": "Agendamento do processamento", + "notif_processing_schedule_desc": "Executar o envio de notificações pelos fornecedores de forma agendada.", + "notif_send_now": "Enviar agora", + "notif_providers": "Fornecedores", + "notif_providers_desc": "Crie, edite, teste e ative fornecedores de notificações.", + "notif_providers_channels_info": "Cada fornecedor pode subscrever os canais de Lembretes, Alertas e Informação.", + "notif_add_provider": "Adicionar fornecedor", + "notif_empty_title": "Ainda não há fornecedores de notificações configurados", + "notif_empty_desc": "Adicione um fornecedor para receber notificações agendadas de Lembretes, Alertas ou Informação.", + "notif_load_failed": "Falha ao carregar os fornecedores de notificações", + "notif_select_provider_type": "Selecione um tipo de fornecedor", + "notif_select_channel": "Selecione pelo menos um canal de notificações", + "notif_provider_updated": "Fornecedor atualizado com sucesso", + "notif_provider_created": "Fornecedor criado com sucesso", + "notif_provider_deleted": "Fornecedor eliminado com sucesso", + "notif_provider_delete_failed": "Falha ao eliminar o fornecedor", + "notif_channel_reminder": "Lembrete", + "notif_channel_reminder_desc": "Datas-limite e notificações do tipo lembrete", + "notif_channel_alert": "Alerta", + "notif_channel_alert_desc": "Itens urgentes ou a expirar que precisam de atenção", + "notif_channel_information": "Informação", + "notif_channel_information_desc": "Atualizações informativas gerais", + "notif_provider_enabled": "Ativo", + "notif_provider_test": "Testar fornecedor", + "notif_provider_edit": "Editar fornecedor", + "notif_provider_delete": "Eliminar fornecedor", + "notif_dialog_add_title": "Adicionar fornecedor de notificações", + "notif_dialog_edit_title": "Editar fornecedor de notificações", + "notif_dialog_desc": "Escolha um tipo de fornecedor, configure o destino e subscreva os canais pretendidos. Os fornecedores ficam ativos por predefinição e podem ser desativados nos respetivos cartões.", + "notif_provider_name": "Nome do fornecedor", + "notif_provider_name_placeholder": "Email de resumo diário", + "notif_provider_type": "Tipo de fornecedor", + "notif_provider_type_email": "Email (SMTP)", + "notif_provider_type_webhook": "Webhook", + "notif_provider_type_gotify": "Gotify", + "notif_provider_type_select": "Selecionar tipo de fornecedor", + "notif_dialog_cancel": "Cancelar", + "notif_dialog_create": "Criar fornecedor", + "notif_dialog_update": "Atualizar fornecedor", + "notif_channel_subscriptions": "Subscrições de canais", + "notif_channel_subscriptions_desc": "Escolha os canais de notificações que este fornecedor deve receber.", + "notif_test_title": "Testar fornecedor", + "notif_test_success": "Notificação de teste enviada com sucesso", + "notif_test_email_label": "Email de teste", + "notif_test_email_placeholder": "destinatario@exemplo.com", + "notif_test_email_desc": "Destinatário alternativo opcional para esta mensagem de teste.", + "notif_test_message_label": "Mensagem de teste", + "notif_test_message_placeholder": "Esta é uma notificação de teste do Tracktor", + "notif_test_send": "Enviar teste", + "notif_cron_presets": "Predefinições", + "notif_cron_every_minute": "A cada minuto", + "notif_cron_every_5_min": "A cada 5 minutos", + "notif_cron_every_15_min": "A cada 15 minutos", + "notif_cron_every_30_min": "A cada 30 minutos", + "notif_cron_every_hour": "A cada hora", + "notif_cron_every_2_hours": "A cada 2 horas", + "notif_cron_every_6_hours": "A cada 6 horas", + "notif_cron_every_12_hours": "A cada 12 horas", + "notif_cron_daily_midnight": "Diariamente à meia-noite", + "notif_cron_daily_2am": "Diariamente às 02:00", + "notif_cron_daily_8am": "Diariamente às 08:00", + "notif_cron_daily_noon": "Diariamente ao meio-dia", + "notif_cron_weekly_monday": "Semanalmente (segunda-feira)", + "notif_cron_monthly_1st": "Mensalmente (dia 1)", + "notif_cron_expression_required": "Expressão obrigatória", + "notif_cron_must_have_5_parts": "Tem de ter 5 partes", + "notif_cron_invalid_chars": "Caracteres inválidos", + "notif_cron_valid": "Expressão válida", + "notif_cron_invalid": "Expressão inválida", + "notif_cron_custom": "Agendamento personalizado", + "notif_email_smtp_settings": "Definições do servidor SMTP", + "notif_email_host": "Servidor", + "notif_email_port": "Porta", + "notif_email_use_ssl": "Usar SSL/TLS", + "notif_email_use_ssl_desc": "Ativar ligação segura", + "notif_email_auth": "Autenticação", + "notif_email_username": "Utilizador / email", + "notif_email_password": "Palavra-passe", + "notif_email_password_keep": "Palavra-passe (deixe em branco para manter a atual)", + "notif_email_sender_info": "Informação de remetente/destinatário", + "notif_email_from": "Email do remetente", + "notif_email_from_name": "Nome do remetente (opcional)", + "notif_email_from_name_placeholder": "Notificações do Tracktor", + "notif_email_recipient": "Email do destinatário", + "notif_email_recipient_desc": "Endereço de email do destinatário", + "notif_webhook_config": "Configuração do webhook", + "notif_webhook_url": "URL do webhook", + "notif_webhook_method": "Método HTTP", + "notif_webhook_headers": "Cabeçalhos personalizados (JSON)", + "notif_webhook_headers_desc": "Cabeçalhos adicionais a incluir no pedido do webhook", + "notif_webhook_auth_type": "Tipo de autenticação", + "notif_webhook_auth_none": "Nenhuma", + "notif_webhook_auth_basic": "Basic Auth", + "notif_webhook_auth_bearer": "Token Bearer", + "notif_webhook_auth_apikey": "Chave de API", + "notif_webhook_username": "Utilizador", + "notif_webhook_apikey_header": "Nome do cabeçalho da chave de API", + "notif_gotify_config": "Configuração do servidor Gotify", + "notif_gotify_url": "URL do servidor", + "notif_gotify_url_desc": "URL da sua instância do servidor Gotify", + "notif_gotify_token": "Token da aplicação", + "notif_gotify_token_keep": "Token da aplicação (deixe em branco para manter o atual)", + "notif_gotify_token_desc": "Token de aplicação da sua instância Gotify (não o token de cliente)", + "notif_gotify_priority": "Prioridade (0-10)", + "notif_gotify_priority_desc": "Nível de prioridade da mensagem. Prioridade mais alta = notificação mais destacada", + "notif_cleared_success_one": "Foi removida 1 notificação lida", + "notif_cleared_success_other": "Foram removidas {count} notificações lidas", + "notif_cleared_partial": "Removidas {success}, falharam {failed}", + "notif_clear_failed": "Falha ao remover as notificações lidas", + "notif_all_marked_read": "Todas as notificações foram marcadas como lidas", + "notif_mark_read_failed": "Falha ao marcar as notificações como lidas", + "notif_button_mark_all_read": "Marcar tudo como lido", + "notif_button_clear_read": "Remover lidas", + "notif_button_clear_all_read_title": "Remover todas as notificações lidas", + "notif_status_read": "Lida", + "notif_status_unread": "Não lida", + "notif_due_prefix": "Vence: {date}", + "notif_save_provider_failed": "Falha ao guardar o fornecedor", + "notif_update_provider_failed": "Falha ao atualizar o fornecedor", + "notif_send_all_failed": "Falha ao enviar as notificações", + "notif_send_all_success": "Enviadas {notifCount} notificações para {successCount}/{providerCount} fornecedores ativos", + "notif_confirm_delete": "Tem a certeza de que pretende eliminar \"{name}\"?", + "notif_webhook_bearer_keep": "Token Bearer (deixe em branco para manter o atual)", + "notif_webhook_apikey_keep": "Chave de API (deixe em branco para manter a atual)", + "notif_test_failed": "Falha ao enviar a notificação de teste", + "notif_test_send_desc": "Enviar uma notificação de teste usando {name}", + "notif_cron_every_n_minutes": "A cada {n} minutos", + "notif_cron_hourly_at_minute": "A cada hora, no minuto {n}", + "notif_cron_daily_at": "Diariamente às {time}", + "vehicle_hub_back_to_vehicles": "Voltar aos veículos", + "vehicle_hub_plate_copied": "Matrícula copiada", + "vehicle_hub_insurance_valid_till": "Seguro válido até", + "vehicle_hub_vehicle_type": "Tipo de veículo", + "vehicle_hub_activity_title": "Atividade recente", + "vehicle_hub_activity_empty": "Sem atividade recente", + "vehicle_hub_activity_fuel_added": "Abastecimento adicionado", + "vehicle_hub_activity_maintenance": "Manutenção", + "vehicle_hub_records_count": "{count} registos", + "vehicle_hub_valid_till": "Válido até {date}", + "vehicle_hub_upcoming_count": "{count} próximos", + "vehicle_hub_view_details": "Ver detalhes", + "vehicle_hub_manage_title": "Gerir veículo", + "vehicle_hub_stat_odometer": "Conta-quilómetros", + "vehicle_hub_stat_mileage": "Consumo global", + "vehicle_hub_stat_fuel_logs": "Abastecimentos", + "vehicle_hub_stat_maintenance_logs": "Registos de manutenção", + "col_vehicle": "Veículo", + "overview_chart_pick_vehicle": "Selecione um veículo para ver este gráfico", + "fuel_page_title": "Combustível", + "fuel_page_description": "Acompanhe o consumo e os custos de combustível", + "fuel_stat_used": "Combustível usado", + "fuel_stat_spent": "Total gasto", + "fuel_stat_avg_mileage": "Consumo médio", + "fuel_stat_entries": "Total de registos", + "maintenance_page_title": "Manutenção", + "maintenance_page_description": "Acompanhe o histórico de serviços e as próximas manutenções", + "maintenance_stat_last_service": "Último serviço", + "maintenance_stat_next_service": "Próximo serviço", + "maintenance_stat_odometer": "Conta-quilómetros", + "maintenance_stat_total_services": "Total de serviços", + "maintenance_stat_total_spent": "Total gasto", + "maintenance_stat_due_soon": "Para breve", + "maintenance_tab_overview": "Visão geral", + "maintenance_tab_history": "Histórico de serviços", + "maintenance_timeline_title": "Cronologia de manutenção", + "maintenance_upcoming_empty": "Nada agendado", + "maintenance_history_empty": "Ainda não há histórico de serviços", + "maintenance_next_service_fallback": "Serviço de manutenção geral", + "maintenance_also_upcoming": "Também a chegar", + "reminder_page_title": "Lembretes", + "reminder_page_description": "Antecipe as próximas datas de serviço, seguro e emissões", + "reminder_filter_all": "Todos", + "reminder_filter_all_types": "Todos os tipos", + "reminder_filter_service": "Serviço", + "reminder_filter_puc": "Emissões", + "reminder_filter_insurance": "Seguro", + "reminder_filter_others": "Outros", + "reminder_section_upcoming": "Próximos", + "reminder_section_completed": "Concluídos", + "reminder_section_marked_done": "Marcados como concluídos", + "reminder_empty_title": "Ainda não há lembretes configurados", + "reminder_stat_overdue": "Em atraso", + "reminder_stat_due_soon": "Para breve", + "reminder_stat_upcoming": "Próximos", + "reminder_stat_completed": "Concluídos", + "reminder_calendar_title": "Vista de calendário", + "reminder_quick_actions_title": "Ações rápidas", + "reminder_manage_all_action": "Gerir todos os lembretes", + "reminder_list_title": "Lembretes", + "reminder_list_title_for_date": "Lembretes em {date}", + "reminder_clear_filter": "Limpar", + "reminder_calendar_empty_day": "Não há lembretes nesta data.", + "reports_page_title": "Relatórios", + "reports_page_description": "Custos e exportações da sua frota", + "reports_section_costs": "Custos", + "reports_section_details": "Relatório detalhado", + "reports_section_exports": "Exportações", + "reports_stat_fuel_costs": "Custos de combustível", + "reports_stat_maintenance_costs": "Custos de manutenção", + "reports_chart_breakdown_title": "Repartição de despesas", + "reports_chart_trend_title": "Evolução mensal das despesas", + "reports_chart_trend_unavailable": "A evolução mensal só está disponível para todos os veículos em conjunto", + "reports_export_maintenance_title": "Histórico de manutenção", + "reports_export_maintenance_description": "Exportar o histórico de manutenção em PDF", + "reports_export_maintenance_hint": "Selecione um veículo para exportar o respetivo histórico de manutenção", + "reports_export_data_title": "Exportação completa de dados", + "reports_export_data_description": "Exportar todos os dados da frota em JSON", + "reports_type_fuel": "Combustível", + "reports_type_maintenance": "Manutenção", + "reports_type_compliance": "Conformidade", + "nav_compliance": "Conformidade", + "vehicle_action_add_compliance": "Adicionar documento de conformidade", + "feature_compliance_disabled_title": "Funcionalidade de conformidade desativada", + "feature_compliance_disabled_hint": "Ative esta funcionalidade nas Definições para gerir registos de seguro, emissões, inspeção e registo", + "feature_label_compliance": "Conformidade", + "feature_desc_compliance": "Faça a gestão de registos de seguro, emissões, inspeção e registo", + "compliance_type_insurance": "Seguro", + "compliance_type_emissions": "Emissões / poluição", + "compliance_type_roadworthiness": "Inspeção técnica / segurança", + "compliance_type_registration": "Registo / imposto de circulação", + "compliance_type_other": "Outro", + "compliance_field_policy_number": "Número da apólice", + "compliance_field_certificate_number": "Número do certificado", + "compliance_field_registration_number": "Número de registo", + "compliance_field_document_number": "Número do documento", + "compliance_field_provider": "Seguradora", + "compliance_field_testing_center": "Centro de testes", + "compliance_field_inspection_center": "Centro de inspeção", + "compliance_field_issuing_authority": "Entidade emissora", + "compliance_recurrence_type_fixed": "Data de fim fixa", + "compliance_recurrence_type_yearly": "Renova anualmente", + "compliance_recurrence_type_monthly": "Renova mensalmente", + "compliance_recurrence_type_no_end": "Sem data de fim", + "compliance_form_type_label": "Tipo de conformidade", + "compliance_form_type_desc": "Que tipo de documento de conformidade é este", + "compliance_form_other_label_label": "Nome do tipo", + "compliance_form_other_label_desc": "Dê um nome a este tipo de conformidade, ex.: \"WOF (Nova Zelândia)\" ou \"TÜV (Alemanha)\"", + "compliance_form_attachment_label": "Documento", + "compliance_form_attachment_desc": "Carregue o documento", + "compliance_form_issuer_desc": "A seguradora, centro de inspeção ou entidade que emitiu este documento", + "compliance_form_document_number_desc": "O número impresso no documento", + "compliance_form_start_date_label": "Data de início", + "compliance_form_start_date_desc": "Data em que este documento entra em vigor", + "compliance_form_recurrence_type_label": "Como deve renovar-se?", + "compliance_form_recurrence_type_desc": "Tipo de renovação deste documento", + "compliance_form_recurrence_interval_desc": "Com que frequência o documento se renova", + "compliance_form_end_date_label": "Data de fim", + "compliance_form_end_date_desc": "Data em que este documento expira", + "compliance_form_cost_label": "Custo", + "compliance_form_cost_desc": "Custo deste documento, se aplicável", + "compliance_form_notes_label": "Notas adicionais", + "compliance_form_notes_desc": "Informações adicionais", + "compliance_form_notes_placeholder": "Adicione mais detalhes...", + "compliance_form_error_fix": "Corrija os erros do formulário antes de submeter.", + "compliance_toast_saved": "Documento de conformidade guardado com sucesso", + "compliance_toast_updated": "Documento de conformidade atualizado com sucesso", + "compliance_toast_error_prefix": "Erro ao guardar: ", + "compliance_list_empty": "Não foram encontrados documentos de conformidade para este veículo.", + "compliance_col_cost": "Custo", + "compliance_col_start_date": "Data de início", + "compliance_col_end_date": "Data de fim", + "compliance_col_next_due": "Próxima renovação", + "compliance_col_recurrence": "Recorrência", + "compliance_col_notes": "Notas", + "compliance_col_view_document": "Ver documento", + "compliance_menu_open": "Abrir menu", + "compliance_menu_edit": "Editar", + "compliance_menu_delete": "Eliminar", + "compliance_menu_sheet_title": "Atualizar documento de conformidade", + "compliance_delete_success": "Documento de conformidade eliminado.", + "compliance_delete_error": "Ocorreu um erro ao eliminar o documento de conformidade.", + "compliance_page_title": "Conformidade", + "compliance_page_description": "Acompanhe o seguro, as emissões, a inspeção e o registo dos veículos", + "compliance_add_action": "Adicionar documento de conformidade", + "compliance_filter_all_types": "Todos os tipos", + "compliance_filter_all": "Todos", + "compliance_filter_valid": "Válidos", + "compliance_filter_expiring_soon": "A expirar em breve", + "compliance_filter_expired": "Expirados", + "compliance_stat_total": "Total", + "compliance_stat_valid": "Válidos", + "compliance_stat_expiring_soon": "A expirar em breve", + "compliance_stat_expired": "Expirados", + "compliance_cta_heading": "Mantenha os seus veículos em conformidade", + "compliance_cta_description": "Mantenha os documentos de conformidade atualizados para evitar coimas e circular dentro da lei.", + "vehicle_hub_other_compliance_valid_till": "Outra conformidade válida até", + "vehicle_hub_activity_compliance_updated": "Documento de conformidade atualizado", + "vehicle_hub_activity_document_prefix": "Doc. n.º ", + "reports_stat_compliance_costs": "Custos de conformidade", + "compliance_col_document": "Conformidade", + "compliance_col_status": "Estado", + "compliance_col_days_left": "Dias restantes" +} diff --git a/i18n/project.inlang/settings.json b/i18n/project.inlang/settings.json index 5dec532c..600dae07 100644 --- a/i18n/project.inlang/settings.json +++ b/i18n/project.inlang/settings.json @@ -8,5 +8,5 @@ "pathPattern": "./messages/{locale}.json" }, "baseLocale": "en", - "locales": ["en", "ar", "hi", "es", "fr", "de", "it", "hu", "fi", "ro", "ru"] + "locales": ["en", "ar", "hi", "es", "fr", "de", "it", "hu", "fi", "ro", "ru", "pt-PT"] } diff --git a/src/lib/helper/settings-form.helper.ts b/src/lib/helper/settings-form.helper.ts index 5a3884ba..643a29f4 100644 --- a/src/lib/helper/settings-form.helper.ts +++ b/src/lib/helper/settings-form.helper.ts @@ -78,7 +78,8 @@ export function createSettingsOptions( hu: 'Magyar', fi: 'Suomi', ro: 'Română', - ru: 'Русский' + ru: 'Русский', + 'pt-PT': 'Português (Portugal)' }; return { From c0aa3925139854a6d37ca21e80fd67ce07b9004e Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 13 Aug 2026 23:05:20 +0000 Subject: [PATCH 8/9] Apply native review of post-rebase strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 'revisão' terminology for scheduled services; 'Histórico de manutenção' for the history tab - 'Abastecimento registado' for the fuel activity entry - Compliance feature hint/description harmonized with 'registo do veículo' phrasing - 'Distribuição de despesas' for the breakdown chart - Vehicle type 'rulote', reworded reminders page description, minor wording fixes Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01YXazaegVWZdeKziwMzPKPG --- i18n/messages/pt-PT.json | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/i18n/messages/pt-PT.json b/i18n/messages/pt-PT.json index ccfbd998..f98917d4 100644 --- a/i18n/messages/pt-PT.json +++ b/i18n/messages/pt-PT.json @@ -366,7 +366,7 @@ "vehicle_type_bus": "Autocarro", "vehicle_type_farm_vehicle": "Veículo agrícola", "vehicle_type_yacht": "Iate", - "vehicle_type_rv": "Autocaravana / caravana", + "vehicle_type_rv": "Autocaravana / rulote", "vehicle_type_other": "Outro", "fuel_type_diesel": "Gasóleo", "fuel_type_petrol": "Gasolina", @@ -499,7 +499,7 @@ "settings_section_feature_flags": "Funcionalidades", "settings_section_feature_flags_desc": "Ative ou desative os principais módulos da aplicação", "settings_notifications_desc": "Configure as subscrições de fornecedores e a hora diária de processamento para envio agendado.", - "settings_localization_desc": "Defina o idioma e as preferências regionais.", + "settings_localization_desc": "Defina o idioma e as suas preferências regionais.", "settings_advanced_desc": "Afine a interface com estilos personalizados.", "settings_nav_desc_personalization": "Tema, apresentação e estilo", "settings_nav_desc_localization": "Idioma e formatos regionais", @@ -647,13 +647,13 @@ "notif_cron_every_n_minutes": "A cada {n} minutos", "notif_cron_hourly_at_minute": "A cada hora, no minuto {n}", "notif_cron_daily_at": "Diariamente às {time}", - "vehicle_hub_back_to_vehicles": "Voltar aos veículos", + "vehicle_hub_back_to_vehicles": "Voltar à lista de veículos", "vehicle_hub_plate_copied": "Matrícula copiada", "vehicle_hub_insurance_valid_till": "Seguro válido até", "vehicle_hub_vehicle_type": "Tipo de veículo", "vehicle_hub_activity_title": "Atividade recente", "vehicle_hub_activity_empty": "Sem atividade recente", - "vehicle_hub_activity_fuel_added": "Abastecimento adicionado", + "vehicle_hub_activity_fuel_added": "Abastecimento registado", "vehicle_hub_activity_maintenance": "Manutenção", "vehicle_hub_records_count": "{count} registos", "vehicle_hub_valid_till": "Válido até {date}", @@ -673,25 +673,25 @@ "fuel_stat_avg_mileage": "Consumo médio", "fuel_stat_entries": "Total de registos", "maintenance_page_title": "Manutenção", - "maintenance_page_description": "Acompanhe o histórico de serviços e as próximas manutenções", - "maintenance_stat_last_service": "Último serviço", - "maintenance_stat_next_service": "Próximo serviço", + "maintenance_page_description": "Acompanhe o histórico de manutenção e as próximas revisões", + "maintenance_stat_last_service": "Última revisão", + "maintenance_stat_next_service": "Próxima revisão", "maintenance_stat_odometer": "Conta-quilómetros", - "maintenance_stat_total_services": "Total de serviços", + "maintenance_stat_total_services": "Total de revisões", "maintenance_stat_total_spent": "Total gasto", "maintenance_stat_due_soon": "Para breve", "maintenance_tab_overview": "Visão geral", - "maintenance_tab_history": "Histórico de serviços", + "maintenance_tab_history": "Histórico de manutenção", "maintenance_timeline_title": "Cronologia de manutenção", "maintenance_upcoming_empty": "Nada agendado", - "maintenance_history_empty": "Ainda não há histórico de serviços", - "maintenance_next_service_fallback": "Serviço de manutenção geral", + "maintenance_history_empty": "Ainda não há histórico de manutenção", + "maintenance_next_service_fallback": "Revisão geral", "maintenance_also_upcoming": "Também a chegar", "reminder_page_title": "Lembretes", - "reminder_page_description": "Antecipe as próximas datas de serviço, seguro e emissões", + "reminder_page_description": "Antecipe as próximas datas de manutenções, seguros e impostos", "reminder_filter_all": "Todos", "reminder_filter_all_types": "Todos os tipos", - "reminder_filter_service": "Serviço", + "reminder_filter_service": "Manutenção", "reminder_filter_puc": "Emissões", "reminder_filter_insurance": "Seguro", "reminder_filter_others": "Outros", @@ -717,7 +717,7 @@ "reports_section_exports": "Exportações", "reports_stat_fuel_costs": "Custos de combustível", "reports_stat_maintenance_costs": "Custos de manutenção", - "reports_chart_breakdown_title": "Repartição de despesas", + "reports_chart_breakdown_title": "Distribuição de despesas", "reports_chart_trend_title": "Evolução mensal das despesas", "reports_chart_trend_unavailable": "A evolução mensal só está disponível para todos os veículos em conjunto", "reports_export_maintenance_title": "Histórico de manutenção", @@ -731,9 +731,9 @@ "nav_compliance": "Conformidade", "vehicle_action_add_compliance": "Adicionar documento de conformidade", "feature_compliance_disabled_title": "Funcionalidade de conformidade desativada", - "feature_compliance_disabled_hint": "Ative esta funcionalidade nas Definições para gerir registos de seguro, emissões, inspeção e registo", + "feature_compliance_disabled_hint": "Ative esta funcionalidade nas Definições para gerir o seguro, as emissões, a inspeção e o registo do veículo", "feature_label_compliance": "Conformidade", - "feature_desc_compliance": "Faça a gestão de registos de seguro, emissões, inspeção e registo", + "feature_desc_compliance": "Faça a gestão do seguro, das emissões, da inspeção e do registo do veículo", "compliance_type_insurance": "Seguro", "compliance_type_emissions": "Emissões / poluição", "compliance_type_roadworthiness": "Inspeção técnica / segurança", From d272b1795bffb561025e4330d6c90a510ef3affc Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Aug 2026 18:34:48 +0000 Subject: [PATCH 9/9] Refine pt-PT strings after native review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - reminder_page_description: describe the scheduled events that actually exist in Portugal (revisão, inspeção, seguro, imposto de circulação) instead of "emissões"/"impostos" - auth_login_title: gender-inclusive "Bem-vindo(a) de volta" - maintenance_also_upcoming: "Em breve" Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_015pTw3AsFM2b5TYHERhZe34 --- i18n/messages/pt-PT.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/i18n/messages/pt-PT.json b/i18n/messages/pt-PT.json index f98917d4..676561a0 100644 --- a/i18n/messages/pt-PT.json +++ b/i18n/messages/pt-PT.json @@ -23,7 +23,7 @@ "auth_login_loading": "A iniciar sessão...", "auth_signup_loading": "A criar conta...", "auth_password_mismatch": "As palavras-passe não coincidem!", - "auth_login_title": "Bem-vindo de volta", + "auth_login_title": "Bem-vindo(a) de volta", "auth_login_subtitle": "Inicie sessão para manter os seus veículos, abastecimentos e documentos em dia.", "settings_tab_personalization": "Personalização", "settings_tab_interface": "Interface", @@ -686,9 +686,9 @@ "maintenance_upcoming_empty": "Nada agendado", "maintenance_history_empty": "Ainda não há histórico de manutenção", "maintenance_next_service_fallback": "Revisão geral", - "maintenance_also_upcoming": "Também a chegar", + "maintenance_also_upcoming": "Em breve", "reminder_page_title": "Lembretes", - "reminder_page_description": "Antecipe as próximas datas de manutenções, seguros e impostos", + "reminder_page_description": "Antecipe as próximas datas de revisão, inspeção, seguro e imposto de circulação", "reminder_filter_all": "Todos", "reminder_filter_all_types": "Todos os tipos", "reminder_filter_service": "Manutenção",