Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions frontend/scripts/check-hardcoded-i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
// This list is an incremental ratchet: once a user-facing screen has been
// migrated, literal English UI copy must not return to it.
const guardedFiles = [
'src/lib/dialogs/PomodoroSettingsModal.svelte',
'src/lib/layout/DashboardCustomizationSidebar.svelte',
'src/lib/pages/Homepage.svelte',
'src/lib/features/workflows/WorkflowBuilder.svelte',
Expand Down
46 changes: 23 additions & 23 deletions frontend/src/lib/dialogs/PomodoroSettingsModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
let form = $state({ ...defaultForm });

const projectOptions = $derived([
{ value: '', label: 'Select a project...' },
{ value: '', label: t('time.pomodoro.selectProject') },
...projects
.filter((project) => project.status === 'Active')
.map((project) => ({
Expand Down Expand Up @@ -111,7 +111,7 @@
loaded = true;
} catch (err) {
console.warn('[pomodoro-settings] failed to load settings:', err);
error = `Failed to load settings: ${err?.message || err}`;
error = t('time.pomodoro.loadError', { error: err?.message || err });
} finally {
loading = false;
}
Expand All @@ -135,10 +135,10 @@
try {
const call = await getInvoke();
await call('save_pomodoro_settings', { settings: toSettings(form) });
status = 'Settings saved';
status = t('time.pomodoro.settingsSaved');
} catch (err) {
console.warn('[pomodoro-settings] failed to save settings:', err);
error = `Failed to save settings: ${err?.message || err}`;
error = t('time.pomodoro.saveError', { error: err?.message || err });
} finally {
saving = false;
}
Expand Down Expand Up @@ -171,34 +171,34 @@
>
<div class="flex items-center justify-between border-b px-6 py-4" style="border-color: var(--ds-border);">
<div>
<h2 id="pomodoro-settings-title" class="text-lg font-semibold">Pomodoro Settings</h2>
<p class="mt-1 text-sm" style="color: var(--ds-text-subtle);">Configure desktop timer behavior and automatic time logging.</p>
<h2 id="pomodoro-settings-title" class="text-lg font-semibold">{t('time.pomodoro.title')}</h2>
<p class="mt-1 text-sm" style="color: var(--ds-text-subtle);">{t('time.pomodoro.subtitle')}</p>
</div>
<Button variant="ghost" icon={X} onclick={close} title={t('common.close')} />
</div>

<div class="px-6 py-5">
{#if loading}
<p class="text-sm" style="color: var(--ds-text-subtle);">Loading settings...</p>
<p class="text-sm" style="color: var(--ds-text-subtle);">{t('time.pomodoro.loadingSettings')}</p>
{:else}
<div class="grid gap-6 md:grid-cols-3">
<section class="md:col-span-2">
<div class="mb-3 flex items-center gap-2">
<Clock class="h-5 w-5" style="color: var(--ds-icon);" />
<h3 class="text-sm font-semibold uppercase tracking-wide" style="color: var(--ds-text-subtle);">Timer</h3>
<h3 class="text-sm font-semibold uppercase tracking-wide" style="color: var(--ds-text-subtle);">{t('time.pomodoro.timer')}</h3>
</div>

<div class="grid gap-x-4 md:grid-cols-2">
<FormField label="Work duration" helper="Minutes per focus session">
<FormField label={t('time.pomodoro.workDuration')} helper={t('time.pomodoro.workDurationHelper')}>
<Input type="number" min="1" step="1" bind:value={form.work_duration_minutes} />
</FormField>
<FormField label="Short break" helper="Minutes between work sessions">
<FormField label={t('time.pomodoro.shortBreak')} helper={t('time.pomodoro.shortBreakHelper')}>
<Input type="number" min="1" step="1" bind:value={form.short_break_minutes} />
</FormField>
<FormField label="Long break" helper="Minutes after a completed cycle">
<FormField label={t('time.pomodoro.longBreak')} helper={t('time.pomodoro.longBreakHelper')}>
<Input type="number" min="1" step="1" bind:value={form.long_break_minutes} />
</FormField>
<FormField label="Sessions before long break" helper="Completed work sessions">
<FormField label={t('time.pomodoro.sessionsBeforeLongBreak')} helper={t('time.pomodoro.sessionsBeforeLongBreakHelper')}>
<Input type="number" min="1" step="1" bind:value={form.cycles_before_long_break} />
</FormField>
</div>
Expand All @@ -207,35 +207,35 @@
<section>
<div class="mb-3 flex items-center gap-2">
<Play class="h-5 w-5" style="color: var(--ds-icon);" />
<h3 class="text-sm font-semibold uppercase tracking-wide" style="color: var(--ds-text-subtle);">Behavior</h3>
<h3 class="text-sm font-semibold uppercase tracking-wide" style="color: var(--ds-text-subtle);">{t('time.pomodoro.behavior')}</h3>
</div>
<div class="space-y-4 rounded border p-4" style="border-color: var(--ds-border); background-color: var(--ds-surface);">
<Toggle bind:checked={form.auto_start_break} label="Auto-start breaks" />
<Toggle bind:checked={form.auto_start_work} label="Auto-start work" />
<Toggle bind:checked={form.auto_start_break} label={t('time.pomodoro.autoStartBreaks')} />
<Toggle bind:checked={form.auto_start_work} label={t('time.pomodoro.autoStartWork')} />
</div>
</section>
</div>

<section class="mt-6">
<div class="mb-3 flex items-center gap-2">
<FileText class="h-5 w-5" style="color: var(--ds-icon);" />
<h3 class="text-sm font-semibold uppercase tracking-wide" style="color: var(--ds-text-subtle);">Logging</h3>
<h3 class="text-sm font-semibold uppercase tracking-wide" style="color: var(--ds-text-subtle);">{t('time.pomodoro.logging')}</h3>
</div>

<div class="rounded border p-4" style="border-color: var(--ds-border); background-color: var(--ds-surface);">
<Toggle bind:checked={form.auto_log_enabled} label="Automatically log completed work sessions" />
<Toggle bind:checked={form.auto_log_enabled} label={t('time.pomodoro.autoLogCompletedSessions')} />

{#if form.auto_log_enabled}
<div class="mt-4 grid gap-x-4 md:grid-cols-2">
<FormField label="Project" helper="Active time projects from this workspace server">
<FormField label={t('time.pomodoro.project')} helper={t('time.pomodoro.projectHelper')}>
<Select
bind:value={form.log_project_id}
options={projectOptions}
placeholder={projectsLoaded ? 'Select a project...' : 'Loading projects...'}
placeholder={projectsLoaded ? t('time.pomodoro.selectProject') : t('time.pomodoro.loadingProjects')}
/>
</FormField>
<FormField label="Description" helper="Used for new worklog entries">
<Input bind:value={form.log_description} placeholder="Pomodoro session" />
<FormField label={t('time.pomodoro.description')} helper={t('time.pomodoro.descriptionHelper')}>
<Input bind:value={form.log_description} placeholder={t('time.pomodoro.sessionPlaceholder')} />
</FormField>
</div>
{/if}
Expand All @@ -255,8 +255,8 @@
</div>

<div class="flex justify-end gap-3 border-t px-6 py-4" style="border-color: var(--ds-border);">
<Button variant="default" size="small" onclick={close}>Cancel</Button>
<Button variant="primary" size="small" onclick={save} loading={saving} disabled={loading}>Save Settings</Button>
<Button variant="default" size="small" onclick={close}>{t('time.pomodoro.cancel')}</Button>
<Button variant="primary" size="small" onclick={save} loading={saving} disabled={loading}>{t('time.pomodoro.saveSettings')}</Button>
</div>
</div>
</ModalBackdrop>
31 changes: 31 additions & 0 deletions frontend/src/lib/locales/de/time.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,37 @@ export default {
end: 'Ende',
duration: 'Dauer',
durationHelperText: 'Geben Sie Startzeit + Dauer (2h) ein, um die Endzeit automatisch zu berechnen, oder geben Sie Start + Ende ein, um die Dauer automatisch zu berechnen. Zeitformate: 1h, 30m, 1h30m, 2h15m, 1d (=8h)',
pomodoro: {
title: 'Pomodoro-Einstellungen',
subtitle: 'Konfigurieren Sie das Verhalten des Desktop-Timers und die automatische Zeiterfassung.',
loadingSettings: 'Einstellungen werden geladen...',
loadError: 'Einstellungen konnten nicht geladen werden: {error}',
settingsSaved: 'Einstellungen gespeichert',
saveError: 'Einstellungen konnten nicht gespeichert werden: {error}',
timer: 'Timer',
workDuration: 'Arbeitsdauer',
workDurationHelper: 'Minuten pro Fokus-Sitzung',
shortBreak: 'Kurze Pause',
shortBreakHelper: 'Minuten zwischen Arbeitssitzungen',
longBreak: 'Lange Pause',
longBreakHelper: 'Minuten nach einem abgeschlossenen Zyklus',
sessionsBeforeLongBreak: 'Sitzungen bis zur langen Pause',
sessionsBeforeLongBreakHelper: 'Abgeschlossene Arbeitssitzungen',
behavior: 'Verhalten',
autoStartBreaks: 'Pausen automatisch starten',
autoStartWork: 'Arbeit automatisch starten',
logging: 'Zeiterfassung',
autoLogCompletedSessions: 'Abgeschlossene Arbeitssitzungen automatisch erfassen',
project: 'Projekt',
projectHelper: 'Aktive Zeiterfassungsprojekte auf diesem Server',
selectProject: 'Projekt auswählen...',
loadingProjects: 'Projekte werden geladen...',
description: 'Beschreibung',
descriptionHelper: 'Wird für neue Zeiteinträge verwendet',
sessionPlaceholder: 'Pomodoro-Sitzung',
cancel: 'Abbrechen',
saveSettings: 'Einstellungen speichern',
},
onboarding: {
title: 'Zeiterfassung einrichten',
subtitle: 'Lassen Sie uns Ihre erste Kundenorganisation und Ihr erstes Projekt erstellen',
Expand Down
32 changes: 32 additions & 0 deletions frontend/src/lib/locales/en/time.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,38 @@ export default {
durationHelperText:
'Enter start time + duration (2h) to auto-calculate end time, or enter start + end times to auto-calculate duration. Time formats: 1h, 30m, 1h30m, 2h15m, 1d (=8h)',

pomodoro: {
title: 'Pomodoro Settings',
subtitle: 'Configure desktop timer behavior and automatic time logging.',
loadingSettings: 'Loading settings...',
loadError: 'Failed to load settings: {error}',
settingsSaved: 'Settings saved',
saveError: 'Failed to save settings: {error}',
timer: 'Timer',
workDuration: 'Work duration',
workDurationHelper: 'Minutes per focus session',
shortBreak: 'Short break',
shortBreakHelper: 'Minutes between work sessions',
longBreak: 'Long break',
longBreakHelper: 'Minutes after a completed cycle',
sessionsBeforeLongBreak: 'Sessions before long break',
sessionsBeforeLongBreakHelper: 'Completed work sessions',
behavior: 'Behavior',
autoStartBreaks: 'Auto-start breaks',
autoStartWork: 'Auto-start work',
logging: 'Logging',
autoLogCompletedSessions: 'Automatically log completed work sessions',
project: 'Project',
projectHelper: 'Active time projects from this workspace server',
selectProject: 'Select a project...',
loadingProjects: 'Loading projects...',
description: 'Description',
descriptionHelper: 'Used for new worklog entries',
sessionPlaceholder: 'Pomodoro session',
cancel: 'Cancel',
saveSettings: 'Save Settings',
},

// Timesheet
timesheet: {
title: 'Timesheet',
Expand Down
32 changes: 32 additions & 0 deletions frontend/src/lib/locales/ru/time.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,38 @@ export default {
durationHelperText:
'Введите время начала и продолжительность (2h), чтобы рассчитать время окончания, или время начала и окончания, чтобы рассчитать продолжительность. Форматы: 1h, 30m, 1h30m, 2h15m, 1d (=8h)',

pomodoro: {
title: 'Настройки Pomodoro',
subtitle: 'Настройте поведение таймера в настольном приложении и автоматический учёт времени.',
loadingSettings: 'Загрузка настроек…',
loadError: 'Не удалось загрузить настройки: {error}',
settingsSaved: 'Настройки сохранены',
saveError: 'Не удалось сохранить настройки: {error}',
timer: 'Таймер',
workDuration: 'Длительность работы',
workDurationHelper: 'Минут на один сеанс концентрации',
shortBreak: 'Короткий перерыв',
shortBreakHelper: 'Минут между рабочими сеансами',
longBreak: 'Длинный перерыв',
longBreakHelper: 'Минут после завершённого цикла',
sessionsBeforeLongBreak: 'Сеансов до длинного перерыва',
sessionsBeforeLongBreakHelper: 'Завершённые рабочие сеансы',
behavior: 'Поведение',
autoStartBreaks: 'Автоматически запускать перерывы',
autoStartWork: 'Автоматически запускать работу',
logging: 'Учёт времени',
autoLogCompletedSessions: 'Автоматически записывать завершённые рабочие сеансы',
project: 'Проект',
projectHelper: 'Активные проекты учёта времени на сервере этого рабочего пространства',
selectProject: 'Выберите проект…',
loadingProjects: 'Загрузка проектов…',
description: 'Описание',
descriptionHelper: 'Используется для новых записей времени',
sessionPlaceholder: 'Сеанс Pomodoro',
cancel: 'Отмена',
saveSettings: 'Сохранить настройки',
},

timesheet: {
title: 'Табель',
subtitle: 'Обзор табеля за неделю',
Expand Down
Loading