Split i18n catalogues into per-domain modules

sv.ts/en.ts were single 602-line files that every feature had to edit,
making concurrent work on unrelated screens collide constantly. Split
both into per-domain modules (common, auth, calendar, dashboard,
settings, plan, wishEditor, tips) composed by an index that preserves
the existing `import { sv } from './sv'` specifier, so no consumer
changes.

Typing still catches drift in both directions: each en module is checked
against TranslationKey, and the composed catalogue must satisfy
Record<TranslationKey, string>.

All 433 keys and their values are byte-identical to the originals,
verified by diffing the parsed catalogues against the pre-split files.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RXMhc9nT6sNz1SL4j8dznL
This commit is contained in:
2026-09-14 18:54:27 +02:00
parent 7f031f2087
commit bd996245ba
20 changed files with 1017 additions and 1204 deletions
+13
View File
@@ -0,0 +1,13 @@
export const auth = {
'auth.createAccountButton': 'Create account',
'auth.createAccountTitle': 'Create account',
'auth.emailPlaceholder': 'Email',
'auth.genericError': 'Something went wrong',
'auth.haveAccountButton': 'Already have an account',
'auth.loadingEllipsis': 'Loading…',
'auth.loginButton': 'Log in',
'auth.loginTitle': 'Log in',
'auth.namePlaceholder': 'Name',
'auth.passwordPlaceholder': 'Password',
'auth.registerButton': 'Register',
} as const
+62
View File
@@ -0,0 +1,62 @@
export const calendar = {
'calendar.advanceMonthAria': '{month} - click to advance month',
'calendar.advanceYearAria': '{year} - click to advance year',
'calendar.deleteError': 'Failed to delete the planned day',
'calendar.legendDoubleDay': 'Double day',
'calendar.legendIncomeBased': 'Income-based rate (sjukpenningnivå)',
'calendar.legendKlamdag': 'Bridge day',
'calendar.legendMinimumRate': 'Minimum rate (lägstanivå)',
'calendar.legendOverride': 'Exception (working/day off)',
'calendar.legendRedDay': 'Public holiday',
'calendar.legendTitle': 'Legend',
'calendar.legendVacation': 'Vacation',
'calendar.loading': 'Loading calendar...',
'calendar.nextMonthAria': 'Next month',
'calendar.overrideError': 'Failed to update the exception',
'calendar.overrideModeActiveLabel': 'Stop editing days',
'calendar.overrideModeHint': 'Click a day to mark it as a working day or a day off. Click a marked day again to reset it.',
'calendar.overrideModeLabel': 'Mark working/day off',
'calendar.partner': 'Partner',
'calendar.prevMonthAria': 'Previous month',
'calendar.saveError': 'Failed to save the planned days',
'calendar.weekdayFri': 'Fri',
'calendar.weekdayMon': 'Mon',
'calendar.weekdaySat': 'Sat',
'calendar.weekdaySun': 'Sun',
'calendar.weekdayThu': 'Thu',
'calendar.weekdayTue': 'Tue',
'calendar.weekdayWed': 'Wed',
'calendar.you': 'You',
'calendarDay.ariaWithEvents': '{date} with {count} event(s)',
'calendarDay.klamdagAria': 'bridge day',
'calendarDay.overrideFreeAria': 'marked as a day off (exception)',
'calendarDay.overrideWorkingAria': 'marked as a working day (exception)',
'calendarEvent.dismissAria': 'Dismiss {leaveType}',
'plannedDayModal.cancelButton': 'Cancel',
'plannedDayModal.closeAria': 'Close',
'plannedDayModal.confirmDelete': 'Are you sure you want to delete this planned day?',
'plannedDayModal.deleteButton': 'Delete',
'plannedDayModal.deleteError': 'Failed to delete planned day',
'plannedDayModal.deletingButton': 'Deleting…',
'plannedDayModal.doubleDayHint': 'Double days do not apply to vacation',
'plannedDayModal.doubleDayLabel': 'Double day (both parents taking leave)',
'plannedDayModal.editTitle': 'Edit Planned Day',
'plannedDayModal.lagstaOption': 'Lägstanivå (minimum-rate, 90-day tier)',
'plannedDayModal.leaveTypeLabel': 'Leave Type',
'plannedDayModal.newTitle': 'Plan a Day',
'plannedDayModal.parentLabel': 'Parent',
'plannedDayModal.rangeTitle': 'Plan {count} days',
'plannedDayModal.saveButton': 'Save',
'plannedDayModal.saveError': 'Failed to save planned day',
'plannedDayModal.savingButton': 'Saving…',
'plannedDayModal.sjukpenningOption': 'Sjukpenningnivå (income-based, 390-day tier)',
'plannedDayModal.vacationOption': 'Vacation',
'redDaysList.effectiveFree': 'Off',
'redDaysList.effectiveWorking': 'Working day',
'redDaysList.emptyYear': 'No public holidays or exceptions this year.',
'redDaysList.loading': 'Loading public holidays...',
'redDaysList.nextWindow': 'Next 4 years',
'redDaysList.overrideFree': 'Exception: day off',
'redDaysList.overrideWorking': 'Exception: working day',
'redDaysList.prevWindow': 'Previous 4 years',
} as const
+23
View File
@@ -0,0 +1,23 @@
export const common = {
'app.name': 'Föräldraledigplannerare',
'common.cancel': 'Cancel',
'common.close': 'Close',
'common.delete': 'Delete',
'common.deleting': 'Deleting…',
'common.loadingEllipsis': 'Loading…',
'common.save': 'Save',
'common.saving': 'Saving…',
'footer.copyright': '© {year} Föräldraledigplannerare. All rights reserved.',
'leaveType.lagsta': 'Lägstanivå (minimum rate)',
'leaveType.sjukpenning': 'Sjukpenningnivå (income-based)',
'leaveType.unknown': 'Unknown',
'leaveType.vacation': 'Vacation',
'nav.calendar': 'Calendar',
'nav.logout': 'Log out',
'nav.logoutAria': 'Log out',
'nav.overview': 'Overview',
'nav.plan': 'Plan',
'nav.selectChildAria': 'Select child',
'nav.settings': 'Settings',
'nav.tips': 'Tips',
} as const
+41
View File
@@ -0,0 +1,41 @@
export const dashboard = {
'dashboard.addChildButton': 'Add child',
'dashboard.addChildIntro': 'You have no children registered yet. Add your first child to get started.',
'dashboard.addChildTitle': 'Add child',
'dashboard.addingChild': 'Adding...',
'dashboard.birthdayLabel': 'Birthday',
'dashboard.childNameLabel': 'Child\'s name',
'dashboard.createChildError': 'Could not create child',
'dashboard.daysLeft': 'Days left',
'dashboard.enterManually': 'Enter details manually',
'dashboard.expiringAtB4': 'Total expiring at age 4 (sum of all parents)',
'dashboard.expiringAtB4ForParent': 'Expiring at age 4 – {name}',
'dashboard.expiringAtB4ParentFallback': 'Parent {number}',
'dashboard.fetchFromFk': 'Fetch from Försäkringskassan',
'dashboard.fillAllFields': 'Fill in all fields',
'dashboard.loading': 'Loading...',
'dashboard.namePlaceholder': 'Name',
'dashboard.overviewTitle': 'Overview',
'dashboard.plannedDaysTitle': 'Planned days',
'dashboard.remainingUntilB4Title': 'Remaining until age 4',
'dashboard.saveManualFetchError': 'Could not save the details',
'dashboard.usedDays': 'Used days',
'daysBreakdown.daysHeader': 'Days',
'daysBreakdown.empty': 'No days registered yet',
'daysBreakdown.typeHeader': 'Leave type',
'overviewMetrics.defaultTitle': 'Overview',
'parentalLeaveBreakdown.dubbeldagarLeft': 'Double days left',
'parentalLeaveBreakdown.empty': 'No data fetched yet — press Fetch from Försäkringskassan.',
'parentalLeaveBreakdown.lagstaNiva': 'Minimum rate',
'parentalLeaveBreakdown.remainingHeader': 'Remaining',
'parentalLeaveBreakdown.reservedNote': '{reserved} of your days are reserved and cannot be transferred to the other parent (up to {transferable} days can be transferred).',
'parentalLeaveBreakdown.sjukpenning': 'Sjukpenningnivå (income-based)',
'parentalLeaveBreakdown.sourceManual': 'Manually entered',
'parentalLeaveBreakdown.sourceScraped': 'Fetched from Försäkringskassan',
'parentalLeaveBreakdown.totalHeader': 'Total',
'parentalLeaveBreakdown.transferableDays': 'Transferable days',
'parentalLeaveBreakdown.typeHeader': 'Type',
'progressChart.age': 'Age: {age}',
'progressChart.title': 'Parental leave — progress',
'progressChart.weeksStat': '{current} / {target} weeks',
} as const
+33
View File
@@ -0,0 +1,33 @@
import type { TranslationKey } from '../sv'
import { common } from './common'
import { auth } from './auth'
import { calendar } from './calendar'
import { dashboard } from './dashboard'
import { settings } from './settings'
import { plan } from './plan'
import { wishEditor } from './wishEditor'
import { tips } from './tips'
/**
* English message catalogue.
*
* Typed as `Record<TranslationKey, string>` by composing all module
* subsets. The `satisfies` keyword verifies that all keys across the modules
* cover the full `TranslationKey` set.
*
* Domain terms are translated for meaning, not word-for-word — see
* ARCHITECTURE notes for the glossary (sjukpenningnivå is the income-based
* rate, not sick leave; lägstanivå is the flat minimum rate; dubbeldagar
* are "double days"; röd dag is a public holiday; klämdag is a
* "bridge day").
*/
export const en = {
...common,
...auth,
...calendar,
...dashboard,
...settings,
...plan,
...wishEditor,
...tips,
} satisfies Record<TranslationKey, string>
+117
View File
@@ -0,0 +1,117 @@
export const plan = {
'plan.addAtLeastOneWish': 'Add at least one wish above to suggest a plan.',
'plan.addWishError': 'Could not add wish',
'plan.calculating': 'Calculating...',
'plan.intro': 'Describe how you want to be on leave — for example 6 weeks every summer and 4 weeks every Christmas — and get a suggested plan showing exactly which days are already free, which cost a vacation day, and which cost a parental-benefit day.',
'plan.loading': 'Loading planning...',
'plan.proposeButton': 'Suggest plan',
'plan.removeWishError': 'Could not remove wish',
'plan.title': 'Planning',
'plan.updateWishError': 'Could not save wish',
'plan.wishesTitle': 'Your wishes',
'planResults.age4ProjectionsIntro': 'Here\'s what the 4th birthday looks like if this plan is taken as proposed — life may of course work out differently.',
'planResults.age4ProjectionsTitle': 'At the child\'s 4th birthday, if this plan is followed',
'planResults.applyButton': 'Use plan',
'planResults.applySavedPrefix': 'The plan has been saved!',
'planResults.applyingButton': 'Saving...',
'planResults.balancesTitle': 'Remaining balances after the plan',
'planResults.cancelButton': 'Cancel',
'planResults.collisionDateHeader': 'Date',
'planResults.collisionExistingHeader': 'Existing type',
'planResults.collisionProposedHeader': 'Proposed type',
'planResults.confirmOverwriteButton': 'Yes, replace the existing days',
'planResults.confirmOverwriteIntro': 'The following days are already planned and will be replaced:',
'planResults.confirmOverwriteTitle': 'Conflict with existing days',
'planResults.createdClause': '{count} new {dayWord} created',
'planResults.daySingular': 'day',
'planResults.dayTypeFree': 'free days (weekend/public holiday)',
'planResults.dayTypeLagsta': 'parental-benefit days (lägstanivå, minimum rate)',
'planResults.dayTypeSjukpenning': 'parental-benefit days (sjukpenningnivå, income-based)',
'planResults.dayTypeVacation': 'vacation days',
'planResults.daysPlural': 'days',
'planResults.detailTitle': 'Leave periods in detail',
'planResults.dubbeldagarLeftHeader': 'Double days left',
'planResults.expiringAtB4Header': 'Expiring',
'planResults.explanationDetailFree': '{free_days} fully free days (weekend/public holiday)',
'planResults.explanationDetailLagsta': '{lagsta_days} parental-benefit days (lägstanivå, minimum rate)',
'planResults.explanationDetailSjukpenning': '{sjukpenning_days} parental-benefit days (sjukpenningnivå, income-based)',
'planResults.explanationDetailVacationAndFp': 'you keep your salary for {vacation_days} days and save {fp_days} parental-benefit days',
'planResults.explanationDetailVacationOnly': '{vacation_days} vacation days',
'planResults.explanationShortfallSuffix': ' ({shortfall_days} days short)',
'planResults.explanationSummary': '{wish_name} {year} — {weeks_wished} weeks wished, {weeks_funded} weeks funded',
'planResults.fourthBirthdayHeader': '4th birthday',
'planResults.freeDaySingular': 'free day',
'planResults.freeDaysPlural': 'free days',
'planResults.fullyFunded': 'Fully funded',
'planResults.funded': 'funded',
'planResults.lagstaLeftHeader': 'Lägstanivå days left',
'planResults.leavesHeader': 'Leave periods',
'planResults.noWindowsInHorizon': 'No windows within the planning horizon.',
'planResults.parentHeader': 'Parent',
'planResults.parentalDaysTitle': 'Parental-benefit days',
'planResults.previewBanner': 'This is a suggestion — nothing is saved automatically. You can adjust your wishes above and suggest a new plan as many times as you like.',
'planResults.projectedLeftHeader': 'Projected left',
'planResults.rejectionCollisionsNeedReplace': '{count} day(s) already planned differently; pass replace=true to overwrite',
'planResults.rejectionConflictingDuplicate': 'Conflicting duplicate entries for {date} (child {child_id}, parent {parent_personal_data_uuid}) in the same batch',
'planResults.rejectionDubbeldagBatchQuotaExceeded': 'This batch would result in {projected_total} double days, the max is {max_dubbeldagar}',
'planResults.rejectionDubbeldagInvalid': 'The double day for {date} could not be approved',
'planResults.rejectionDubbeldagQuotaReached': 'The double-days quota ({max_dubbeldagar} days) has already been reached',
'planResults.rejectionDubbeldagWindowExceeded': 'Double days are only allowed within the child\'s first {months_limit} months (deadline {deadline})',
'planResults.rejectionInsufficientBalance': 'This batch needs {needed} more "{tier}" day(s) but only {remaining} remain',
'planResults.rejectionInvalidDayType': 'Day {index} ({date}): invalid day type "{day_type}"',
'planResults.rejectionOutsideEligibleWindow': '{date}: outside the child\'s eligible window ({birth_date} – {hard_expiry})',
'planResults.rejectionsClause': '. Rejected: {rejections}',
'planResults.remedyCarryVacationForward': '{spare_total} vacation days from previous years can be carried forward',
'planResults.remedyLowerPriorityWish': 'Lowering {wish_name} from {from_weeks} to {to_weeks} weeks frees up {freed_days} days',
'planResults.remedyReducePreschoolReserve': 'Reducing the preschool planning-day reserve ({reserved} reserved) frees up {reserved} days',
'planResults.remedyShiftWindowIntoFreeDays': 'Moving {wish_name} closer to a weekend frees up {shift_gain} days',
'planResults.replacedClause': ', {count} {dayWord} replaced',
'planResults.savableAfterB4Header': 'Savable',
'planResults.shortfallCouldNotBeFunded': '{days} {dayWord} could not be funded.',
'planResults.shortfallLabel': 'Shortfall:',
'planResults.sjukpenningLeftHeader': 'Sjukpenningnivå days left',
'planResults.skippedFreeClause': ', {count} {dayWord} skipped',
'planResults.skippedIdenticalClause': ', {count} {dayWord} skipped (already identical)',
'planResults.strategyDubbeldag': 'Double days — both parents home at the same time',
'planResults.strategyParentSwap': 'Parents alternate',
'planResults.strategyPrefix': 'Strategy:',
'planResults.strategySolo': 'One parent home',
'planResults.strategyUnplaced': 'Could not be placed — no free slot was found',
'planResults.surplusAdviceBodyFrontLoadEarlyYears': '{parent_name} has a large surplus ({days_involved} parental-benefit days) — take more days now while the child is still small and you are home anyway, rather than spreading them thinly until the 4th birthday.',
'planResults.surplusAdviceBodyShiftMixToFp': '{parent_name} could swap {days_involved} vacation day(s) for parental-benefit days in this plan — the parental-benefit days would otherwise be forfeited at the 4th birthday, while the vacation days would not.',
'planResults.surplusAdviceBodyUseLessVacation': '{parent_name} could take {days_involved} fewer vacation day(s) ({years_text}) without going below the statutory minimum ({min_vacation_days_per_year} days/year) — save them instead to cover parental-benefit days that would otherwise be forfeited.',
'planResults.surplusAdviceBodyWishMoreLeave': '{parent_name} can afford {weeks} more week(s) of leave ({days_involved} parental-benefit days would otherwise be forfeited at the child\'s 4th birthday) — add a week in the summer or an autumn break.',
'planResults.surplusAdviceFrontLoadEarlyYears': 'Take more leave while the child is small',
'planResults.surplusAdviceIntro': 'This plan leaves days unused that would otherwise be lost at the child\'s 4th birthday. A few suggestions:',
'planResults.surplusAdviceShiftMixToFp': 'Spend parental-benefit days instead of vacation',
'planResults.surplusAdviceTitle': 'You have unused days',
'planResults.surplusAdviceUseLessVacation': 'Save fewer vacation days',
'planResults.surplusAdviceWishMoreLeave': 'Wish for more leave',
'planResults.totalAvailableHeader': 'Total available',
'planResults.usedHeader': 'Used',
'planResults.vacationAssumedBadge': 'Assumed',
'planResults.vacationAssumedPrompt': 'No value is recorded for this year — the statutory 25 days has been assumed. Confirm or edit it in Settings.',
'planResults.vacationDaysTitle': 'Vacation days',
'planResults.warningBodyDaysLostAtAge4': '{parent_name} risks losing {expiring_days} days at the child\'s 4th birthday ({fourth_birthday}) unless more days are used before then.',
'planResults.warningBodySgiRisk': '{parent_name} risks their SGI protection for the week starting {week_start} ({days_planned} day(s) planned, at least {min_days_per_week} required).',
'planResults.warningBodyVacationExpiring': '{parent_name} has {saved_days_in} saved vacation day(s) from {year} at risk of being forfeited.',
'planResults.warningDaysLostAtAge4': 'Days at risk of being lost at age 4',
'planResults.warningSgiRisk': 'Risk to SGI protection',
'planResults.warningVacationExpiring': 'Vacation days at risk of being lost',
'planResults.warningsTitle': 'Warnings',
'planResults.weekSingular': 'week',
'planResults.weeksUnit': 'weeks',
'planResults.wished': 'wished',
'planResults.yearHeader': 'Year',
'planResults.yearOverviewTitle': 'Overview by year',
'planningGoalSelector.balanced': 'Balanced',
'planningGoalSelector.balancedHelp': 'A trade-off between time at home and income.',
'planningGoalSelector.legend': 'Planning goal',
'planningGoalSelector.maxMoney': 'Most money',
'planningGoalSelector.maxMoneyHelp': 'Protect your income, e.g. by placing vacation around weekends and public holidays.',
'planningGoalSelector.maxTime': 'Most time at home',
'planningGoalSelector.maxTimeHelp': 'Save days and extend your total leave time, with lower income now.',
'planningModeSelector.couple': 'Me and my partner',
'planningModeSelector.legend': 'Are you planning alone or together with a partner?',
'planningModeSelector.solo': 'Just me',
} as const
+131
View File
@@ -0,0 +1,131 @@
export const settings = {
'childBirthdayInput.birthDateLabel': 'Date of birth',
'childBirthdayInput.defaultLabel': 'Child\'s birth date',
'childBirthdayInput.preschoolStartLabel': 'Preschool start (optional)',
'dayOverridesInput.addButton': 'Add exception',
'dayOverridesInput.addSectionTitle': 'Add exception',
'dayOverridesInput.addingButton': 'Adding...',
'dayOverridesInput.charCount': '{count}/280',
'dayOverridesInput.dateLabel': 'Date',
'dayOverridesInput.empty': 'You have no calendar exceptions yet.',
'dayOverridesInput.noteFieldLabel': 'Note (optional)',
'dayOverridesInput.noteLabel': 'Note: {note}',
'dayOverridesInput.notePlaceholder': 'E.g. Worked on Christmas Day',
'dayOverridesInput.offStatus': 'I\'m off this day',
'dayOverridesInput.statusLegend': 'Status',
'dayOverridesInput.workingStatus': 'I\'m working this day',
'manualFetchModal.cancelButton': 'Cancel',
'manualFetchModal.closeAria': 'Close',
'manualFetchModal.daysRemaining': 'Days remaining:',
'manualFetchModal.daysUsedLabel': 'Days used',
'manualFetchModal.description': 'Enter your parental leave information from Försäkringskassan manually if automatic fetching is unavailable.',
'manualFetchModal.dubbeldagarLabel': 'Dubbeldagar left (0-60)',
'manualFetchModal.lagstaUsedLabel': 'Lägstanivå (minimum-rate, 90-day tier) used',
'manualFetchModal.remainingBreakdownTitle': 'Remaining Days Breakdown',
'manualFetchModal.reservedDaysLabel': 'Reserved days left',
'manualFetchModal.saveButton': 'Save',
'manualFetchModal.saveError': 'Failed to save manual data',
'manualFetchModal.savingButton': 'Saving…',
'manualFetchModal.sjukpenningUsedLabel': 'Sjukpenningnivå (income-based, 390-day tier) used',
'manualFetchModal.tierBreakdownTitle': 'Tier Breakdown',
'manualFetchModal.title': 'Enter Parental Leave Data',
'manualFetchModal.totalDaysLabel': 'Total days (0-480)',
'manualFetchModal.totalDaysSectionTitle': 'Total Days',
'manualFetchModal.transferableDaysLabel': 'Transferable days left',
'parentProfileInput.employed': 'Employed',
'parentProfileInput.employmentStatusLabel': 'Employment status',
'parentProfileInput.hourly': 'Hourly wage',
'parentProfileInput.jobseeking': 'Job seeking',
'parentProfileInput.monthly': 'Monthly salary',
'parentProfileInput.none': 'None',
'parentProfileInput.salaryTypeLabel': 'Salary type',
'parentProfileInput.selectEmploymentStatus': 'Select employment status',
'parentProfileInput.selectSalaryType': 'Select salary type',
'qrModal.authenticating': 'Authenticating…',
'qrModal.cancelButton': 'Cancel',
'qrModal.cancelled': 'The session was cancelled.',
'qrModal.closeAria': 'Close modal',
'qrModal.closeButton': 'Close',
'qrModal.errorLabel': 'Error:',
'qrModal.fetching': 'Fetching data from FK…',
'qrModal.qrAlt': 'BankID QR code',
'qrModal.qrInstruction': 'Open the BankID app and scan the QR code:',
'qrModal.statusLabel': 'Status:',
'qrModal.success': 'Done! Data fetched from Försäkringskassan.',
'qrModal.title': 'Fetch from Försäkringskassan',
'settings.addPartnerButton': 'Add partner',
'settings.addPartnerError': 'Could not add partner',
'settings.addPartnerSuccess': 'Partner added!',
'settings.addingPartner': 'Adding...',
'settings.calendarSectionTitle': 'Calendar',
'settings.cancelButton': 'Cancel',
'settings.childBirthDateLabel': 'Child\'s birth date',
'settings.childSectionTitle': 'Child',
'settings.dayOverridesHelp': 'The planner is based on the Swedish calendar (public holidays, bridge days, Christmas Eve, Midsummer Eve and Whitsun Eve are normally days off). Here you can enter exceptions for your workplace — if you have to work on Christmas Day, or are off on days that are otherwise working days.',
'settings.dayOverridesSectionTitle': 'Calendar exceptions',
'settings.languageAutoOption': 'Automatic (browser language)',
'settings.languageEnglishOption': 'English',
'settings.languageLabel': 'Välj språk / Select language',
'settings.languageSectionTitle': 'Språk / Language',
'settings.languageSwedishOption': 'Svenska',
'settings.loading': 'Loading settings...',
'settings.membersLoading': 'Loading members…',
'settings.noChildSelected': 'No child selected yet.',
'settings.partnerActionErrorNotFound': 'Could not find the partner. Reload the page and try again.',
'settings.partnerIntro': 'Add a partner to plan parental leave together.',
'settings.partnerLinkedIntro': 'Your partner is linked to this workspace.',
'settings.partnerNameInvalid': 'The partner\'s name is invalid.',
'settings.partnerNamePlaceholder': 'Partner\'s name',
'settings.partnerNameRequired': 'Enter a name for the partner',
'settings.partnerSectionTitle': 'Partner',
'settings.planningHelp': 'Your planning goal, and whether you plan alone or together with a partner, control how the planner suggests distributing days.',
'settings.planningSectionTitle': 'Planning',
'settings.preschoolHelp': 'Preschools usually close for about 6 days a year for planning. Enter how many days your preschool has, so they are reserved in the plan.',
'settings.preschoolPlanningDaysLabel': 'Preschool planning days per year',
'settings.profileHelp': 'Your salary type and employment status are used to estimate your SGI and plan your leave.',
'settings.profileSectionTitle': 'Your profile',
'settings.redDaysHelp': 'A list of public holidays under the Swedish calendar, together with your own exceptions — four years at a time.',
'settings.redDaysSectionTitle': 'Public holidays',
'settings.removeBlockerLeaveWishes': 'leave wishes',
'settings.removeBlockerParentalLeave': 'recorded parental leave',
'settings.removeBlockerPlannedLeave': 'planned leave days',
'settings.removeBlockerVacationDays': 'recorded vacation days',
'settings.removeConfirmButton': 'Yes, remove',
'settings.removeConfirmPrompt': 'Remove {name} from the workspace?',
'settings.removePartnerButton': 'Remove',
'settings.removePartnerError': 'Could not remove the partner',
'settings.removePartnerErrorHasDependentData': 'Can\'t remove — there is recorded: {blockers}. Remove or move this first.',
'settings.removePartnerErrorHasLogin': 'Can\'t remove — this person has their own account and login.',
'settings.removePartnerErrorSelf': 'You can\'t remove yourself from the workspace.',
'settings.renameButton': 'Rename',
'settings.renamePartnerError': 'Could not rename',
'settings.saveChildButton': 'Save child\'s details',
'settings.saveChildError': 'Could not save the child\'s details',
'settings.saveChildSuccess': 'Child\'s details saved!',
'settings.savePlanningButton': 'Save planning',
'settings.savePlanningError': 'Could not save planning settings',
'settings.savePlanningSuccess': 'Planning settings saved!',
'settings.saveProfileButton': 'Save your profile',
'settings.saveProfileError': 'Could not save your profile',
'settings.saveProfileSuccess': 'Your profile was saved!',
'settings.saveRenameButton': 'Save name',
'settings.saveVacationError': 'Could not save vacation days',
'settings.saveVacationSuccess': 'Vacation days for {year} saved!',
'settings.selectedChildLabel': 'Selected child:',
'settings.showWeekNumbers': 'Show week numbers',
'settings.title': 'Settings',
'settings.vacationHelp': 'Enter vacation days per year. In the first year you are usually home more and have fewer days to spend on vacation, while later years have your full annual allotment. This controls how much time the planner has to work with.',
'settings.vacationSectionTitle': 'Vacation days',
'settings.youBadge': '(You)',
'vacationDaysList.empty': 'No vacation days registered.',
'vacationDaysList.itemDays': '{count} days',
'vacationDaysList.loading': 'Loading vacation days…',
'vacationDaysList.savedSuffix': '(+{count} saved)',
'vacationDaysTable.assumedBadge': 'Assumed',
'vacationDaysTable.assumedPrompt': 'No value is recorded for this year — the statutory 25 days has been assumed. Confirm or edit below.',
'vacationDaysTable.empty': 'No years to show yet.',
'vacationDaysTable.saveButton': 'Save',
'vacationDaysTable.savedDaysHeader': 'Saved days carried in',
'vacationDaysTable.vacationDaysHeader': 'Vacation days',
'vacationDaysTable.yearHeader': 'Year',
} as const
+31
View File
@@ -0,0 +1,31 @@
export const tips = {
'tip.aria': 'Tip: {title}',
'tip.balanceBetweenParents.body': '{leading_parent} has taken {gap_days} more days than {lagging_parent}. Consider evening out the split.',
'tip.balanceBetweenParents.title': 'Imbalance between parents',
'tip.dismissAria': 'Dismiss: {title}',
'tip.lagstaNivaCoverage.body': '{parent_name} has only {sjukpenning_left} days left at sjukpenningnivå (income-based) but {lagsta_left} days left at lägstanivå (minimum rate).',
'tip.lagstaNivaCoverage.title': 'Cover the gap with lägstanivå',
'tip.longBreakParentSwap.body': '{parent_name} is covering less than half of "{break_name}" ({start_date}–{end_date}). Let {other_parent_name} take part of the period.',
'tip.longBreakParentSwap.title': 'Consider alternating',
'tip.preserveForAge4.body': '{parent_name} risks losing {expiring_days} days when the child turns 4 ({fourth_birthday}). Only 96 days can be saved after that.',
'tip.preserveForAge4.title': 'Days at risk of being lost at age 4',
'tip.reserveForPreschoolPlanningDays.body': '{parent_name} has {days_left} days left, which barely covers the preschool\'s {buffer_days} planning days. Reserve days ahead of time.',
'tip.reserveForPreschoolPlanningDays.title': 'Reserve days for preschool planning days',
'tip.sgiMinimumAfterAge1.body': '{parent_name} is planning fewer than {min_days_per_week} parental-benefit days a week over the coming month, which can affect SGI protection.',
'tip.sgiMinimumAfterAge1.title': 'Risk to SGI protection',
'tip.skipFpFirst12Months.body': '{parent_name} has parental-benefit leave planned before the child turns 1. With the "most time at home" goal it can pay off to save those days for later.',
'tip.skipFpFirst12Months.title': 'Save parental benefit for later',
'tip.stretchTimeAtHome.body': '{parent_name} is planning {weekly_intensity} days a week over the coming month, leaving {projected_left} days at age 4.',
'tip.stretchTimeAtHome.title': 'Stretch out your time at home',
'tip.useDubbeldagarStrategically.body': 'You both have parental-benefit leave planned on {date} but it isn\'t marked as a double day (dubbeldag).',
'tip.useDubbeldagarStrategically.title': 'Use a double day',
'tip.useVacationBeforeExpiry.body': '{parent_name} has {saved_days} saved vacation days from {year} that risk being lost if not used.',
'tip.useVacationBeforeExpiry.title': 'Vacation days at risk of expiring',
'tip.wrapRedDaysWithVacation.body': '{parent_name} has parental-benefit leave planned near a holiday cluster ({cluster_start}–{cluster_end}). A vacation day around the public holidays can extend the break.',
'tip.wrapRedDaysWithVacation.title': 'Make the most of public holidays',
'tip.wrapWeekendWithVacation.body': '{parent_name} has parental-benefit leave planned on Friday {friday} and Monday {monday}. A vacation day in between makes for a longer break.',
'tip.wrapWeekendWithVacation.title': 'Make the most of the weekend',
'tips.empty': 'No tips yet. Great job planning your parental leave!',
'tips.loading': 'Loading tips...',
'tips.title': 'Optimization Tips',
} as const
+58
View File
@@ -0,0 +1,58 @@
export const wishEditor = {
'wishEditor.adjustBound': 'Adjust search range',
'wishEditor.adjustDates': 'Adjust dates',
'wishEditor.bothParents': 'Both parents',
'wishEditor.boundEndsLabel': 'to',
'wishEditor.boundStartsLabel': 'Search range from',
'wishEditor.boundTooShortError': 'The search range is shorter than the {weeks} weeks wished — choose a longer range or fewer weeks.',
'wishEditor.customFlexButton': '+ Custom search range',
'wishEditor.customFlexName': 'Custom search range',
'wishEditor.customLeaveButton': '+ Custom leave',
'wishEditor.customLeaveName': 'Custom leave',
'wishEditor.eitherParent': 'Either parent',
'wishEditor.emptyState': 'No leave wishes yet. Choose a suggestion above to get started.',
'wishEditor.endsLabel': 'Ends',
'wishEditor.firstYearLabel': 'First year',
'wishEditor.flexBadge': 'whenever it fits best',
'wishEditor.flexPresetsLabel': 'Quick picks — search within a season ("whenever it fits best"):',
'wishEditor.hideDates': 'Hide dates',
'wishEditor.lastYearLabel': 'Last year',
'wishEditor.modeFixed': 'Fixed dates',
'wishEditor.modeFlexible': 'Whenever it fits best',
'wishEditor.modeFlexibleExplainer': 'The engine picks the best week inside the search range below by itself — it looks for the period with the most röda dagar (public holidays) and klämdagar (bridge days), since that costs the fewest semesterdagar (vacation days). A recurring wish is re-picked every year (Easter moves, for example), and the suggestion always needs confirming in the Plan tab before it is saved, just like any other plan.',
'wishEditor.modeSectionLabel': 'How should this wish be placed?',
'wishEditor.month1': 'January',
'wishEditor.month10': 'October',
'wishEditor.month11': 'November',
'wishEditor.month12': 'December',
'wishEditor.month2': 'February',
'wishEditor.month3': 'March',
'wishEditor.month4': 'April',
'wishEditor.month5': 'May',
'wishEditor.month6': 'June',
'wishEditor.month7': 'July',
'wishEditor.month8': 'August',
'wishEditor.month9': 'September',
'wishEditor.nameAria': 'Name for {name}',
'wishEditor.parentLabel': 'Parent',
'wishEditor.presetHostlov': 'Autumn break (höstlov)',
'wishEditor.presetJullov': 'Christmas break',
'wishEditor.presetSommar': 'Summer',
'wishEditor.priorityLabel': 'Priority',
'wishEditor.recurEveryYear': 'Repeats every year',
'wishEditor.removeButton': 'Remove',
'wishEditor.saveButton': 'Save',
'wishEditor.saveFailedStatus': 'Could not save — your edit is kept, try again.',
'wishEditor.savedStatus': 'Saved',
'wishEditor.savingButton': 'Saving...',
'wishEditor.seasonHost': 'Autumn',
'wishEditor.seasonJul': 'Christmas',
'wishEditor.seasonSommar': 'Summer',
'wishEditor.seasonVar': 'Spring',
'wishEditor.startsLabel': 'Starts',
'wishEditor.untilAge4': 'Until the child turns 4',
'wishEditor.weekUnit': 'week',
'wishEditor.weeksLabel': 'Weeks',
'wishEditor.weeksUnit': 'weeks',
'wishEditor.wrapsNote': 'Extends into the next year.',
} as const