fix(timeline): pluralize the zeitstrahl meta-line counts

A count of one rendered "1 Briefe" / "1 Ereignisse". Add _singular
companion keys (de/en/es) and select them when the count is exactly one,
following the project's _singular/_plural convention.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-14 12:15:11 +02:00
parent 9665c9c0fc
commit 398babe584
6 changed files with 38 additions and 5 deletions

View File

@@ -1053,6 +1053,8 @@
"timeline_layer_historical_suffix": "historisch",
"timeline_strip_density_caption": "Monats-Dichte",
"timeline_events_count": "{count} Ereignisse",
"timeline_letters_count_singular": "1 Brief",
"timeline_events_count_singular": "1 Ereignis",
"event_editor_new_title": "Neues Ereignis",
"event_editor_edit_title": "Ereignis bearbeiten",
"event_editor_section_when": "Wann",

View File

@@ -1053,6 +1053,8 @@
"timeline_layer_historical_suffix": "historical",
"timeline_strip_density_caption": "Monthly density",
"timeline_events_count": "{count} events",
"timeline_letters_count_singular": "1 letter",
"timeline_events_count_singular": "1 event",
"event_editor_new_title": "New event",
"event_editor_edit_title": "Edit event",
"event_editor_section_when": "When",

View File

@@ -1053,6 +1053,8 @@
"timeline_layer_historical_suffix": "histórico",
"timeline_strip_density_caption": "Densidad mensual",
"timeline_events_count": "{count} eventos",
"timeline_letters_count_singular": "1 carta",
"timeline_events_count_singular": "1 evento",
"event_editor_new_title": "Nuevo evento",
"event_editor_edit_title": "Editar evento",
"event_editor_section_when": "Cuándo",

View File

@@ -80,7 +80,9 @@ describe('message key parity', () => {
'timeline_letter_glyph_label',
'timeline_layer_historical_suffix',
'timeline_strip_density_caption',
'timeline_events_count'
'timeline_events_count',
'timeline_letters_count_singular',
'timeline_events_count_singular'
];
for (const key of requiredKeys) {
expect(de, `missing key in de: ${key}`).toHaveProperty(key);

View File

@@ -18,12 +18,21 @@ const metaLine = $derived.by(() => {
if (meta.firstYear !== null && meta.lastYear !== null) {
segments.push(`${meta.firstYear}${meta.lastYear}`);
}
// A zero-count segment ("0 Briefe") reads as a data error — drop it.
// A zero-count segment ("0 Briefe") reads as a data error — drop it; a count
// of one takes the singular key ("1 Brief"), per the project plural convention.
if (meta.letterCount > 0) {
segments.push(m.timeline_letters_count({ count: meta.letterCount }));
segments.push(
meta.letterCount === 1
? m.timeline_letters_count_singular()
: m.timeline_letters_count({ count: meta.letterCount })
);
}
if (meta.eventCount > 0) {
segments.push(m.timeline_events_count({ count: meta.eventCount }));
segments.push(
meta.eventCount === 1
? m.timeline_events_count_singular()
: m.timeline_events_count({ count: meta.eventCount })
);
}
segments.push(m.timeline_grouping_date());
return segments.join(' · ');

View File

@@ -68,7 +68,7 @@ describe('/zeitstrahl page', () => {
const sub = document.querySelector('[data-testid="timeline-meta"]');
expect(sub).not.toBeNull();
expect(sub?.textContent).not.toContain('');
expect(sub?.textContent).toContain(m.timeline_letters_count({ count: 1 }));
expect(sub?.textContent).toContain(m.timeline_letters_count_singular());
});
it('omits the entire sub-line for an empty timeline (REQ-002)', () => {
@@ -94,4 +94,20 @@ describe('/zeitstrahl page', () => {
expect(sub).not.toBeNull();
expect(sub?.textContent).not.toContain(m.timeline_events_count({ count: 0 }));
});
it('uses singular count labels for exactly one letter and one event (REQ-002)', () => {
render(Page, {
data: pageData(
makeTimelineDTO({
years: [makeYear(1914, [makeEntry({ documentId: 'a' }), event('Geburt')])]
})
)
});
const sub = document.querySelector('[data-testid="timeline-meta"]');
expect(sub?.textContent).toContain(m.timeline_letters_count_singular());
expect(sub?.textContent).toContain(m.timeline_events_count_singular());
// never the "1 Briefe"/"1 Ereignisse" plural forms for a count of one
expect(sub?.textContent).not.toContain(m.timeline_letters_count({ count: 1 }));
expect(sub?.textContent).not.toContain(m.timeline_events_count({ count: 1 }));
});
});