Pluralise counts properly instead of writing dag(ar)
The translate function learns a {count|singular|plural} form, and the
24 strings that hedged with "dag(ar)", "day(s)" or "week(s)" now pick
the right word from the number they interpolate, in both languages.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XBRLomdLK9jF7wU7a8AA6H
This commit is contained in:
@@ -351,12 +351,12 @@ describe('YearRows', () => {
|
|||||||
})
|
})
|
||||||
const wish = screen.getByTestId('year-row-wish-lw-1-2027')
|
const wish = screen.getByTestId('year-row-wish-lw-1-2027')
|
||||||
expect(wish).toHaveTextContent('1 av 2 veckor')
|
expect(wish).toHaveTextContent('1 av 2 veckor')
|
||||||
expect(screen.getByTestId('year-row-shortfall-lw-1-2027')).toHaveTextContent('2 dag(ar) kunde inte finansieras')
|
expect(screen.getByTestId('year-row-shortfall-lw-1-2027')).toHaveTextContent('2 dagar kunde inte finansieras')
|
||||||
expect(screen.getByTestId('year-row-remedy-lw-1-2027-0')).toHaveTextContent(
|
expect(screen.getByTestId('year-row-remedy-lw-1-2027-0')).toHaveTextContent(
|
||||||
'5 semesterdagar från tidigare år kan sparas framåt',
|
'5 semesterdagar från tidigare år kan sparas framåt',
|
||||||
)
|
)
|
||||||
expect(screen.getByTestId('year-row-remedy-lw-1-2027-1')).toHaveTextContent(
|
expect(screen.getByTestId('year-row-remedy-lw-1-2027-1')).toHaveTextContent(
|
||||||
'Sänk Höstlov från 2 till 1 veckor frigör 4 dagar',
|
'Sänk Höstlov från 2 till 1 vecka frigör 4 dagar',
|
||||||
)
|
)
|
||||||
expect(screen.getByTestId('year-row-remedy-lw-1-2027-2')).toHaveTextContent('planRemedies.novel')
|
expect(screen.getByTestId('year-row-remedy-lw-1-2027-2')).toHaveTextContent('planRemedies.novel')
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -118,6 +118,89 @@ describe('LanguageContext', () => {
|
|||||||
'© {year} Föräldraledigplannerare. Alla rättigheter förbehållna.',
|
'© {year} Föräldraledigplannerare. Alla rättigheter förbehållna.',
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('handles plural form with count = 1 (singular)', () => {
|
||||||
|
expect(translate('sv', 'calendar.toastChangedDays', { name: 'Test', count: 1 })).toBe(
|
||||||
|
'Test: 1 dag ändrades',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('handles plural form with count = 0 (plural)', () => {
|
||||||
|
expect(translate('sv', 'calendar.toastChangedDays', { name: 'Test', count: 0 })).toBe(
|
||||||
|
'Test: 0 dagar ändrades',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('handles plural form with count = 2 (plural)', () => {
|
||||||
|
expect(translate('sv', 'calendar.toastChangedDays', { name: 'Test', count: 2 })).toBe(
|
||||||
|
'Test: 2 dagar ändrades',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('handles plural form in English with 1 week', () => {
|
||||||
|
expect(
|
||||||
|
translate('en', 'calendar.toastShortfallNone', {
|
||||||
|
name: 'Test',
|
||||||
|
start: '2026-01-01',
|
||||||
|
end: '2026-12-31',
|
||||||
|
weeksWished: 1,
|
||||||
|
shortfallDays: 5,
|
||||||
|
}),
|
||||||
|
).toBe(
|
||||||
|
'Test (2026-01-01–2026-12-31): none of the 1 week requested could be funded — 5 days short',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('handles plural form in English with 3 weeks', () => {
|
||||||
|
expect(
|
||||||
|
translate('en', 'calendar.toastShortfallNone', {
|
||||||
|
name: 'Test',
|
||||||
|
start: '2026-01-01',
|
||||||
|
end: '2026-12-31',
|
||||||
|
weeksWished: 3,
|
||||||
|
shortfallDays: 5,
|
||||||
|
}),
|
||||||
|
).toBe(
|
||||||
|
'Test (2026-01-01–2026-12-31): none of the 3 weeks requested could be funded — 5 days short',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('handles plural form with 1 day (singular)', () => {
|
||||||
|
expect(
|
||||||
|
translate('en', 'calendar.toastShortfallNone', {
|
||||||
|
name: 'Test',
|
||||||
|
start: '2026-01-01',
|
||||||
|
end: '2026-12-31',
|
||||||
|
weeksWished: 2,
|
||||||
|
shortfallDays: 1,
|
||||||
|
}),
|
||||||
|
).toBe(
|
||||||
|
'Test (2026-01-01–2026-12-31): none of the 2 weeks requested could be funded — 1 day short',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('uses plural form when param is missing', () => {
|
||||||
|
expect(
|
||||||
|
translate('sv', 'calendar.toastChangedDays', { name: 'Test' }),
|
||||||
|
).toBe(
|
||||||
|
'Test: {count} dagar ändrades',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('preserves plain {param} placeholders alongside plural forms', () => {
|
||||||
|
expect(
|
||||||
|
translate('sv', 'calendar.toastShortfallPartial', {
|
||||||
|
name: 'Test',
|
||||||
|
start: '2026-01-01',
|
||||||
|
end: '2026-12-31',
|
||||||
|
weeksFunded: 2,
|
||||||
|
weeksWished: 2,
|
||||||
|
shortfallDays: 0,
|
||||||
|
}),
|
||||||
|
).toBe(
|
||||||
|
'Test (2026-01-01–2026-12-31): endast 2 av 2 veckor finansierades — 0 dagar saknas',
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('isTranslationKey', () => {
|
describe('isTranslationKey', () => {
|
||||||
|
|||||||
@@ -105,9 +105,19 @@ export function toTranslationParams(data: Record<string, unknown>): TranslationP
|
|||||||
|
|
||||||
function interpolate(template: string, params?: TranslationParams): string {
|
function interpolate(template: string, params?: TranslationParams): string {
|
||||||
if (!params) return template
|
if (!params) return template
|
||||||
return template.replace(/\{(\w+)\}/g, (match, key: string) => {
|
// Handle both plain {param} and plural {param|singular|plural} forms.
|
||||||
|
// When the param is the number 1, render singular; otherwise render plural.
|
||||||
|
// If the param is missing or not a number, default to plural.
|
||||||
|
// The regex captures: (1) the key, (2) optional singular form, (3) optional plural form.
|
||||||
|
return template.replace(/\{(\w+)(?:\|([^|}]*)\|([^|}]*))?\}/g, (match, key: string, singular?: string, plural?: string): string => {
|
||||||
const value = params[key]
|
const value = params[key]
|
||||||
return value === undefined ? match : String(value)
|
// If no singular/plural forms given, just interpolate the value
|
||||||
|
if (singular === undefined) {
|
||||||
|
return value === undefined ? match : String(value)
|
||||||
|
}
|
||||||
|
// Plural form: render singular when value is exactly 1, plural otherwise
|
||||||
|
const numValue = Number(value)
|
||||||
|
return !Number.isNaN(numValue) && numValue === 1 ? singular : (plural ?? match)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,16 +70,16 @@ export const calendar = {
|
|||||||
'calendar.periodCreateError': 'Failed to create the period',
|
'calendar.periodCreateError': 'Failed to create the period',
|
||||||
'calendar.syncError': 'Failed to sync the plan',
|
'calendar.syncError': 'Failed to sync the plan',
|
||||||
'calendar.syncingLabel': 'Syncing…',
|
'calendar.syncingLabel': 'Syncing…',
|
||||||
'calendar.toastChangedDays': '{name}: {count} day(s) changed',
|
'calendar.toastChangedDays': '{name}: {count} {count|day|days} changed',
|
||||||
'calendar.toastGenericPeriod': 'The period',
|
'calendar.toastGenericPeriod': 'The period',
|
||||||
'calendar.toastShortfallNone':
|
'calendar.toastShortfallNone':
|
||||||
'{name} ({start}–{end}): none of the {weeksWished} week(s) requested could be funded — {shortfallDays} day(s) short',
|
'{name} ({start}–{end}): none of the {weeksWished} {weeksWished|week|weeks} requested could be funded — {shortfallDays} {shortfallDays|day|days} short',
|
||||||
'calendar.toastShortfallPartial':
|
'calendar.toastShortfallPartial':
|
||||||
'{name} ({start}–{end}): only {weeksFunded} of {weeksWished} week(s) funded — {shortfallDays} day(s) short',
|
'{name} ({start}–{end}): only {weeksFunded} of {weeksWished} weeks funded — {shortfallDays} {shortfallDays|day|days} short',
|
||||||
'calendar.toastShortfallNoneDays':
|
'calendar.toastShortfallNoneDays':
|
||||||
'{name} ({start}–{end}): none of the {daysWished} day(s) requested could be funded — {shortfallDays} day(s) short',
|
'{name} ({start}–{end}): none of the {daysWished} {daysWished|day|days} requested could be funded — {shortfallDays} {shortfallDays|day|days} short',
|
||||||
'calendar.toastShortfallPartialDays':
|
'calendar.toastShortfallPartialDays':
|
||||||
'{name} ({start}–{end}): only {daysFunded} of {daysWished} day(s) funded — {shortfallDays} day(s) short',
|
'{name} ({start}–{end}): only {daysFunded} of {daysWished} days funded — {shortfallDays} {shortfallDays|day|days} short',
|
||||||
'calendar.undoButton': 'Undo',
|
'calendar.undoButton': 'Undo',
|
||||||
'calendar.undoError': 'Failed to undo the change',
|
'calendar.undoError': 'Failed to undo the change',
|
||||||
'calendar.dismissToastAria': 'Dismiss the message',
|
'calendar.dismissToastAria': 'Dismiss the message',
|
||||||
|
|||||||
@@ -6,21 +6,21 @@
|
|||||||
// (`SurplusAdviceTip.tsx`) and `frontend/src/utils/rejectionMessages.ts`
|
// (`SurplusAdviceTip.tsx`) and `frontend/src/utils/rejectionMessages.ts`
|
||||||
// still render.
|
// still render.
|
||||||
export const plan = {
|
export const plan = {
|
||||||
'planResults.remedyBodyCarryVacationForward': '{spare_total} vacation day(s) from earlier years can be carried forward',
|
'planResults.remedyBodyCarryVacationForward': '{spare_total} {spare_total|vacation day|vacation days} from earlier years can be carried forward',
|
||||||
'planResults.remedyBodyLowerPriorityWish': 'Lowering {wish_name} from {from_weeks} to {to_weeks} week(s) frees {days_freed} day(s)',
|
'planResults.remedyBodyLowerPriorityWish': 'Lowering {wish_name} from {from_weeks} to {to_weeks} {to_weeks|week|weeks} frees {days_freed} {days_freed|day|days}',
|
||||||
'planResults.remedyBodyReducePreschoolReserve': 'Reducing the preschool planning-day reserve ({reserved} reserved) frees {days_freed} day(s)',
|
'planResults.remedyBodyReducePreschoolReserve': 'Reducing the preschool planning-day reserve ({reserved} reserved) frees {days_freed} {days_freed|day|days}',
|
||||||
'planResults.remedyBodyShiftWindowIntoFreeDays': 'Moving the period to {new_start_date} – {new_end_date} frees {days_freed} day(s)',
|
'planResults.remedyBodyShiftWindowIntoFreeDays': 'Moving the period to {new_start_date} – {new_end_date} frees {days_freed} {days_freed|day|days}',
|
||||||
'planResults.rejectionCollisionsNeedReplace': '{count} day(s) already planned differently; pass replace=true to overwrite',
|
'planResults.rejectionCollisionsNeedReplace': '{count} {count|day|days} already planned differently; pass replace=true to overwrite',
|
||||||
'planResults.rejectionConflictingDuplicate': 'Conflicting duplicate entries for {date} (child {child_id}, parent {parent_name}) in the same batch',
|
'planResults.rejectionConflictingDuplicate': 'Conflicting duplicate entries for {date} (child {child_id}, parent {parent_name}) in the same batch',
|
||||||
'planResults.rejectionDubbeldagBatchQuotaExceeded': 'This batch would result in {projected_total} double days, the max is {max_dubbeldagar}',
|
'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.rejectionDubbeldagInvalid': 'The double day for {date} could not be approved',
|
||||||
'planResults.rejectionDubbeldagQuotaReached': 'The double-days quota ({max_dubbeldagar} days) has already been reached',
|
'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.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.rejectionInsufficientBalance': 'This batch needs {needed} more "{tier}" day(s) but only {remaining} remain',
|
||||||
'planResults.rejectionInsufficientVacationBalance': '{parent_name} would need {needed} more vacation day(s) in {year}, but only {remaining} remain',
|
'planResults.rejectionInsufficientVacationBalance': '{parent_name} would need {needed} more {needed|vacation day|vacation days} in {year}, but only {remaining} remain',
|
||||||
'planResults.rejectionInvalidDayType': 'Day {index} ({date}): invalid day type "{day_type}"',
|
'planResults.rejectionInvalidDayType': 'Day {index} ({date}): invalid day type "{day_type}"',
|
||||||
'planResults.rejectionOutsideEligibleWindow': '{date}: outside the child\'s eligible window ({birth_date} – {hard_expiry})',
|
'planResults.rejectionOutsideEligibleWindow': '{date}: outside the child\'s eligible window ({birth_date} – {hard_expiry})',
|
||||||
'planResults.shortfallLine': '{shortfall_days} day(s) could not be funded',
|
'planResults.shortfallLine': '{shortfall_days} {shortfall_days|day|days} could not be funded',
|
||||||
'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.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.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.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.',
|
||||||
|
|||||||
@@ -70,16 +70,16 @@ export const calendar = {
|
|||||||
'calendar.periodCreateError': 'Det gick inte att skapa perioden',
|
'calendar.periodCreateError': 'Det gick inte att skapa perioden',
|
||||||
'calendar.syncError': 'Det gick inte att synka planen',
|
'calendar.syncError': 'Det gick inte att synka planen',
|
||||||
'calendar.syncingLabel': 'Synkroniserar…',
|
'calendar.syncingLabel': 'Synkroniserar…',
|
||||||
'calendar.toastChangedDays': '{name}: {count} dag(ar) ändrades',
|
'calendar.toastChangedDays': '{name}: {count} {count|dag|dagar} ändrades',
|
||||||
'calendar.toastGenericPeriod': 'Perioden',
|
'calendar.toastGenericPeriod': 'Perioden',
|
||||||
'calendar.toastShortfallNone':
|
'calendar.toastShortfallNone':
|
||||||
'{name} ({start}–{end}): inget av de {weeksWished} önskade veckorna kunde finansieras — {shortfallDays} dag(ar) saknas',
|
'{name} ({start}–{end}): inget av de {weeksWished} {weeksWished|önskad vecka|önskade veckor} kunde finansieras — {shortfallDays} {shortfallDays|dag|dagar} saknas',
|
||||||
'calendar.toastShortfallPartial':
|
'calendar.toastShortfallPartial':
|
||||||
'{name} ({start}–{end}): endast {weeksFunded} av {weeksWished} veckor finansierades — {shortfallDays} dag(ar) saknas',
|
'{name} ({start}–{end}): endast {weeksFunded} av {weeksWished} veckor finansierades — {shortfallDays} {shortfallDays|dag|dagar} saknas',
|
||||||
'calendar.toastShortfallNoneDays':
|
'calendar.toastShortfallNoneDays':
|
||||||
'{name} ({start}–{end}): inget av de {daysWished} önskade dagarna kunde finansieras — {shortfallDays} dag(ar) saknas',
|
'{name} ({start}–{end}): inget av de {daysWished} {daysWished|önskad dag|önskade dagar} kunde finansieras — {shortfallDays} {shortfallDays|dag|dagar} saknas',
|
||||||
'calendar.toastShortfallPartialDays':
|
'calendar.toastShortfallPartialDays':
|
||||||
'{name} ({start}–{end}): endast {daysFunded} av {daysWished} dagar finansierades — {shortfallDays} dag(ar) saknas',
|
'{name} ({start}–{end}): endast {daysFunded} av {daysWished} dagar finansierades — {shortfallDays} {shortfallDays|dag|dagar} saknas',
|
||||||
'calendar.undoButton': 'Ångra',
|
'calendar.undoButton': 'Ångra',
|
||||||
'calendar.undoError': 'Det gick inte att ångra ändringen',
|
'calendar.undoError': 'Det gick inte att ångra ändringen',
|
||||||
'calendar.dismissToastAria': 'Stäng meddelandet',
|
'calendar.dismissToastAria': 'Stäng meddelandet',
|
||||||
|
|||||||
@@ -6,21 +6,21 @@
|
|||||||
// (`SurplusAdviceTip.tsx`) and `frontend/src/utils/rejectionMessages.ts`
|
// (`SurplusAdviceTip.tsx`) and `frontend/src/utils/rejectionMessages.ts`
|
||||||
// still render.
|
// still render.
|
||||||
export const plan = {
|
export const plan = {
|
||||||
'planResults.remedyBodyCarryVacationForward': '{spare_total} semesterdagar från tidigare år kan sparas framåt',
|
'planResults.remedyBodyCarryVacationForward': '{spare_total} {spare_total|semesterdag|semesterdagar} från tidigare år kan sparas framåt',
|
||||||
'planResults.remedyBodyLowerPriorityWish': 'Sänk {wish_name} från {from_weeks} till {to_weeks} veckor frigör {days_freed} dagar',
|
'planResults.remedyBodyLowerPriorityWish': 'Sänk {wish_name} från {from_weeks} till {to_weeks} {to_weeks|vecka|veckor} frigör {days_freed} {days_freed|dag|dagar}',
|
||||||
'planResults.remedyBodyReducePreschoolReserve': 'Minska förskolans planeringsdagar ({reserved} reserverade) frigör {days_freed} dagar',
|
'planResults.remedyBodyReducePreschoolReserve': 'Minska förskolans planeringsdagar ({reserved} reserverade) frigör {days_freed} {days_freed|dag|dagar}',
|
||||||
'planResults.remedyBodyShiftWindowIntoFreeDays': 'Flytta perioden till {new_start_date} – {new_end_date} frigör {days_freed} dagar',
|
'planResults.remedyBodyShiftWindowIntoFreeDays': 'Flytta perioden till {new_start_date} – {new_end_date} frigör {days_freed} {days_freed|dag|dagar}',
|
||||||
'planResults.rejectionCollisionsNeedReplace': '{count} dag(ar) är redan planerade på annat sätt; skicka replace=true för att skriva över',
|
'planResults.rejectionCollisionsNeedReplace': '{count} {count|dag|dagar} är redan planerade på annat sätt; skicka replace=true för att skriva över',
|
||||||
'planResults.rejectionConflictingDuplicate': 'Motstridiga dubbletter för {date} (barn {child_id}, förälder {parent_name}) i samma omgång',
|
'planResults.rejectionConflictingDuplicate': 'Motstridiga dubbletter för {date} (barn {child_id}, förälder {parent_name}) i samma omgång',
|
||||||
'planResults.rejectionDubbeldagBatchQuotaExceeded': 'Omgången skulle resultera i {projected_total} dubbeldagar, max är {max_dubbeldagar}',
|
'planResults.rejectionDubbeldagBatchQuotaExceeded': 'Omgången skulle resultera i {projected_total} dubbeldagar, max är {max_dubbeldagar}',
|
||||||
'planResults.rejectionDubbeldagInvalid': 'Dubbeldag för {date} kunde inte godkännas',
|
'planResults.rejectionDubbeldagInvalid': 'Dubbeldag för {date} kunde inte godkännas',
|
||||||
'planResults.rejectionDubbeldagQuotaReached': 'Kvoten för dubbeldagar ({max_dubbeldagar} dagar) är redan nådd',
|
'planResults.rejectionDubbeldagQuotaReached': 'Kvoten för dubbeldagar ({max_dubbeldagar} dagar) är redan nådd',
|
||||||
'planResults.rejectionDubbeldagWindowExceeded': 'Dubbeldagar är endast tillåtna inom barnets första {months_limit} månader (senast {deadline})',
|
'planResults.rejectionDubbeldagWindowExceeded': 'Dubbeldagar är endast tillåtna inom barnets första {months_limit} månader (senast {deadline})',
|
||||||
'planResults.rejectionInsufficientBalance': 'Omgången behöver {needed} fler "{tier}"-dagar men endast {remaining} finns kvar',
|
'planResults.rejectionInsufficientBalance': 'Omgången behöver {needed} fler "{tier}"-dagar men endast {remaining} finns kvar',
|
||||||
'planResults.rejectionInsufficientVacationBalance': '{parent_name} skulle behöva {needed} fler semesterdag(ar) {year}, men endast {remaining} finns kvar',
|
'planResults.rejectionInsufficientVacationBalance': '{parent_name} skulle behöva {needed} fler {needed|semesterdag|semesterdagar} {year}, men endast {remaining} finns kvar',
|
||||||
'planResults.rejectionInvalidDayType': 'Dag {index} ({date}): ogiltig dagtyp "{day_type}"',
|
'planResults.rejectionInvalidDayType': 'Dag {index} ({date}): ogiltig dagtyp "{day_type}"',
|
||||||
'planResults.rejectionOutsideEligibleWindow': '{date}: utanför barnets tillåtna period ({birth_date} – {hard_expiry})',
|
'planResults.rejectionOutsideEligibleWindow': '{date}: utanför barnets tillåtna period ({birth_date} – {hard_expiry})',
|
||||||
'planResults.shortfallLine': '{shortfall_days} dag(ar) kunde inte finansieras',
|
'planResults.shortfallLine': '{shortfall_days} {shortfall_days|dag|dagar} kunde inte finansieras',
|
||||||
'planResults.surplusAdviceBodyFrontLoadEarlyYears': '{parent_name} har ett stort överskott ({days_involved} FP-dagar) — ta ut fler dagar nu medan barnet är litet och ni ändå är hemma, istället för att sprida ut dem tunt fram till 4-årsdagen.',
|
'planResults.surplusAdviceBodyFrontLoadEarlyYears': '{parent_name} har ett stort överskott ({days_involved} FP-dagar) — ta ut fler dagar nu medan barnet är litet och ni ändå är hemma, istället för att sprida ut dem tunt fram till 4-årsdagen.',
|
||||||
'planResults.surplusAdviceBodyShiftMixToFp': '{parent_name} kan byta {days_involved} semesterdagar mot föräldrapenningdagar under planen — FP-dagarna går annars förlorade vid 4-årsdagen, medan semestern inte gör det.',
|
'planResults.surplusAdviceBodyShiftMixToFp': '{parent_name} kan byta {days_involved} semesterdagar mot föräldrapenningdagar under planen — FP-dagarna går annars förlorade vid 4-årsdagen, medan semestern inte gör det.',
|
||||||
'planResults.surplusAdviceBodyUseLessVacation': '{parent_name} kan ta ut {days_involved} färre semesterdagar ({years_text}) utan att gå under lägsta uttaget ({min_vacation_days_per_year} dagar/år) — spara dem istället för att täcka FP-dagar som annars går förlorade.',
|
'planResults.surplusAdviceBodyUseLessVacation': '{parent_name} kan ta ut {days_involved} färre semesterdagar ({years_text}) utan att gå under lägsta uttaget ({min_vacation_days_per_year} dagar/år) — spara dem istället för att täcka FP-dagar som annars går förlorade.',
|
||||||
|
|||||||
@@ -1166,7 +1166,7 @@ describe('Calendar', () => {
|
|||||||
|
|
||||||
const toast = await screen.findByTestId('calendar-toast')
|
const toast = await screen.findByTestId('calendar-toast')
|
||||||
expect(toast).toHaveTextContent('7')
|
expect(toast).toHaveTextContent('7')
|
||||||
expect(toast).toHaveTextContent('dagarna')
|
expect(toast).toHaveTextContent('dagar')
|
||||||
expect(toast).not.toHaveTextContent('3 vecko')
|
expect(toast).not.toHaveTextContent('3 vecko')
|
||||||
expect(toast).not.toHaveTextContent('veckorna')
|
expect(toast).not.toHaveTextContent('veckorna')
|
||||||
})
|
})
|
||||||
@@ -1218,7 +1218,7 @@ describe('Calendar', () => {
|
|||||||
fireEvent.click(screen.getByTestId('preset-click'))
|
fireEvent.click(screen.getByTestId('preset-click'))
|
||||||
|
|
||||||
const toast = await screen.findByTestId('calendar-toast')
|
const toast = await screen.findByTestId('calendar-toast')
|
||||||
// What changed (existing "N day(s) changed" summary) ...
|
// What changed (the "N days changed" summary with pluralization) ...
|
||||||
expect(toast).toHaveTextContent('ändrades')
|
expect(toast).toHaveTextContent('ändrades')
|
||||||
// ... and what fell short.
|
// ... and what fell short.
|
||||||
expect(toast).toHaveTextContent('5')
|
expect(toast).toHaveTextContent('5')
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ function summarizeChanges(changes: PlanChange[], wishes: LeaveWish[], t: Transla
|
|||||||
* week-rounded view. A calendar-drawn period sets `targetDays` (an exact
|
* week-rounded view. A calendar-drawn period sets `targetDays` (an exact
|
||||||
* day count); `targetWeeks` on that same wish is just `Math.ceil(days / 7)`,
|
* day count); `targetWeeks` on that same wish is just `Math.ceil(days / 7)`,
|
||||||
* a leftover the API still requires, never what the user actually asked
|
* a leftover the API still requires, never what the user actually asked
|
||||||
* for. Reporting `weeksWished` for those wishes says "3 week(s)" for a
|
* for. Reporting `weeksWished` for those wishes says "3 weeks" for a
|
||||||
* 7-day drag. When `targetDays` is set, report days instead — the figure
|
* 7-day drag. When `targetDays` is set, report days instead — the figure
|
||||||
* the user actually asked for — and only fall back to weeks for wishes that
|
* the user actually asked for — and only fall back to weeks for wishes that
|
||||||
* never had a day-granular target (e.g. the preset rail, which only ever
|
* never had a day-granular target (e.g. the preset rail, which only ever
|
||||||
|
|||||||
Reference in New Issue
Block a user