refactor(person): one author-name fallback, localized
joinNameOrUnknown()/unknownPersonName() in personFormat.ts replace the three hand-rolled '[Unbekannt]' literals (geschichte/utils, GeschichtenCard, personOption) — the fallback is now the i18n key person_unknown (de/en/es), and formatAuthorDisplayName localizes the server-side literal on the pass-through path. Review round 3: Felix, Markus, Leonie (7). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1214,8 +1214,10 @@
|
|||||||
"error_journey_note_too_long": "Die Notiz ist zu lang (maximal 2000 Zeichen).",
|
"error_journey_note_too_long": "Die Notiz ist zu lang (maximal 2000 Zeichen).",
|
||||||
"error_geschichte_title_too_long": "Der Titel ist zu lang (maximal 255 Zeichen).",
|
"error_geschichte_title_too_long": "Der Titel ist zu lang (maximal 255 Zeichen).",
|
||||||
"error_geschichte_intro_too_long": "Die Einleitung ist zu lang (maximal 4000 Zeichen).",
|
"error_geschichte_intro_too_long": "Die Einleitung ist zu lang (maximal 4000 Zeichen).",
|
||||||
|
"person_unknown": "[Unbekannt]",
|
||||||
"error_geschichte_title_too_long": "Der Titel ist zu lang (maximal 255 Zeichen).",
|
"error_geschichte_title_too_long": "Der Titel ist zu lang (maximal 255 Zeichen).",
|
||||||
"error_geschichte_intro_too_long": "Die Einleitung ist zu lang (maximal 4000 Zeichen).",
|
"error_geschichte_intro_too_long": "Die Einleitung ist zu lang (maximal 4000 Zeichen).",
|
||||||
|
"person_unknown": "[Unbekannt]",
|
||||||
"error_journey_document_already_added": "Dieser Brief ist bereits in der Lesereise enthalten.",
|
"error_journey_document_already_added": "Dieser Brief ist bereits in der Lesereise enthalten.",
|
||||||
"error_geschichte_type_immutable": "Der Typ einer Geschichte kann nach der Erstellung nicht mehr geändert werden."
|
"error_geschichte_type_immutable": "Der Typ einer Geschichte kann nach der Erstellung nicht mehr geändert werden."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1214,8 +1214,10 @@
|
|||||||
"error_journey_note_too_long": "The note is too long (maximum 2000 characters).",
|
"error_journey_note_too_long": "The note is too long (maximum 2000 characters).",
|
||||||
"error_geschichte_title_too_long": "The title is too long (maximum 255 characters).",
|
"error_geschichte_title_too_long": "The title is too long (maximum 255 characters).",
|
||||||
"error_geschichte_intro_too_long": "The introduction is too long (maximum 4000 characters).",
|
"error_geschichte_intro_too_long": "The introduction is too long (maximum 4000 characters).",
|
||||||
|
"person_unknown": "[Unknown]",
|
||||||
"error_geschichte_title_too_long": "The title is too long (maximum 255 characters).",
|
"error_geschichte_title_too_long": "The title is too long (maximum 255 characters).",
|
||||||
"error_geschichte_intro_too_long": "The introduction is too long (maximum 4000 characters).",
|
"error_geschichte_intro_too_long": "The introduction is too long (maximum 4000 characters).",
|
||||||
|
"person_unknown": "[Unknown]",
|
||||||
"error_journey_document_already_added": "This letter is already included in the reading journey.",
|
"error_journey_document_already_added": "This letter is already included in the reading journey.",
|
||||||
"error_geschichte_type_immutable": "The type of a story cannot be changed after creation."
|
"error_geschichte_type_immutable": "The type of a story cannot be changed after creation."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1214,8 +1214,10 @@
|
|||||||
"error_journey_note_too_long": "La nota es demasiado larga (máximo 2000 caracteres).",
|
"error_journey_note_too_long": "La nota es demasiado larga (máximo 2000 caracteres).",
|
||||||
"error_geschichte_title_too_long": "El título es demasiado largo (máximo 255 caracteres).",
|
"error_geschichte_title_too_long": "El título es demasiado largo (máximo 255 caracteres).",
|
||||||
"error_geschichte_intro_too_long": "La introducción es demasiado larga (máximo 4000 caracteres).",
|
"error_geschichte_intro_too_long": "La introducción es demasiado larga (máximo 4000 caracteres).",
|
||||||
|
"person_unknown": "[Desconocido]",
|
||||||
"error_geschichte_title_too_long": "El título es demasiado largo (máximo 255 caracteres).",
|
"error_geschichte_title_too_long": "El título es demasiado largo (máximo 255 caracteres).",
|
||||||
"error_geschichte_intro_too_long": "La introducción es demasiado larga (máximo 4000 caracteres).",
|
"error_geschichte_intro_too_long": "La introducción es demasiado larga (máximo 4000 caracteres).",
|
||||||
|
"person_unknown": "[Desconocido]",
|
||||||
"error_journey_document_already_added": "Esta carta ya está incluida en el viaje de lectura.",
|
"error_journey_document_already_added": "Esta carta ya está incluida en el viaje de lectura.",
|
||||||
"error_geschichte_type_immutable": "El tipo de una historia no se puede cambiar después de su creación."
|
"error_geschichte_type_immutable": "El tipo de una historia no se puede cambiar después de su creación."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { m } from '$lib/paraglide/messages.js';
|
|||||||
import type { components } from '$lib/generated/api';
|
import type { components } from '$lib/generated/api';
|
||||||
import { plainExcerpt } from '$lib/shared/utils/extractText';
|
import { plainExcerpt } from '$lib/shared/utils/extractText';
|
||||||
import { formatDate } from '$lib/shared/utils/date';
|
import { formatDate } from '$lib/shared/utils/date';
|
||||||
|
import { formatAuthorName } from './utils';
|
||||||
|
|
||||||
type GeschichteSummary = components['schemas']['GeschichteSummary'];
|
type GeschichteSummary = components['schemas']['GeschichteSummary'];
|
||||||
|
|
||||||
@@ -24,10 +25,7 @@ function formatPublishedDate(g: GeschichteSummary): string | null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function authorName(g: GeschichteSummary): string {
|
function authorName(g: GeschichteSummary): string {
|
||||||
const a = g.author;
|
return formatAuthorName(g.author);
|
||||||
if (!a) return '';
|
|
||||||
const full = [a.firstName, a.lastName].filter(Boolean).join(' ').trim();
|
|
||||||
return full || '[Unbekannt]';
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { formatDate } from '$lib/shared/utils/date';
|
import { formatDate } from '$lib/shared/utils/date';
|
||||||
import { m } from '$lib/paraglide/messages.js';
|
import { m } from '$lib/paraglide/messages.js';
|
||||||
|
import { joinNameOrUnknown, unknownPersonName } from '$lib/person/personFormat';
|
||||||
|
|
||||||
type AuthorSummary = { firstName?: string; lastName?: string };
|
type AuthorSummary = { firstName?: string; lastName?: string };
|
||||||
type DocumentMeta = { documentDate?: string; senderName?: string; receiverName?: string };
|
type DocumentMeta = { documentDate?: string; senderName?: string; receiverName?: string };
|
||||||
@@ -7,13 +8,14 @@ type AuthorView = { displayName: string };
|
|||||||
|
|
||||||
export function formatAuthorName(author: AuthorSummary | null | undefined): string {
|
export function formatAuthorName(author: AuthorSummary | null | undefined): string {
|
||||||
if (!author) return '';
|
if (!author) return '';
|
||||||
const full = [author.firstName, author.lastName].filter(Boolean).join(' ').trim();
|
// Email is no longer exposed — names or the localized fallback only.
|
||||||
// Mirrors the server-side fallback in GeschichteService.toView — email is no longer exposed.
|
return joinNameOrUnknown(author.firstName, author.lastName);
|
||||||
return full || '[Unbekannt]';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatAuthorDisplayName(author: AuthorView | null | undefined): string {
|
export function formatAuthorDisplayName(author: AuthorView | null | undefined): string {
|
||||||
return author?.displayName ?? '';
|
if (!author) return '';
|
||||||
|
// The server-side fallback is the literal '[Unbekannt]' — localize it here.
|
||||||
|
return author.displayName === '[Unbekannt]' ? unknownPersonName() : author.displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatPublishedAt(
|
export function formatPublishedAt(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { formatDate } from '$lib/shared/utils/date';
|
import { formatDate } from '$lib/shared/utils/date';
|
||||||
|
import { m } from '$lib/paraglide/messages.js';
|
||||||
|
|
||||||
type Person = { firstName?: string | null; lastName: string; displayName: string };
|
type Person = { firstName?: string | null; lastName: string; displayName: string };
|
||||||
type DocForMeta = {
|
type DocForMeta = {
|
||||||
@@ -17,6 +18,19 @@ function djb2(str: string): number {
|
|||||||
return Math.abs(hash);
|
return Math.abs(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Localized fallback when a person has no name parts. */
|
||||||
|
export function unknownPersonName(): string {
|
||||||
|
return m.person_unknown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Single source for the join-names-or-fallback rule. Mirrors the server-side
|
||||||
|
* fallback in GeschichteService.toView (which emits the literal '[Unbekannt]').
|
||||||
|
*/
|
||||||
|
export function joinNameOrUnknown(firstName?: string | null, lastName?: string | null): string {
|
||||||
|
return [firstName, lastName].filter(Boolean).join(' ').trim() || unknownPersonName();
|
||||||
|
}
|
||||||
|
|
||||||
export function getInitials(name: string): string {
|
export function getInitials(name: string): string {
|
||||||
const words = name.trim().split(/\s+/).filter(Boolean);
|
const words = name.trim().split(/\s+/).filter(Boolean);
|
||||||
if (words.length === 0) return '';
|
if (words.length === 0) return '';
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { components } from '$lib/generated/api';
|
import type { components } from '$lib/generated/api';
|
||||||
|
import { joinNameOrUnknown } from './personFormat';
|
||||||
|
|
||||||
type Person = components['schemas']['Person'];
|
type Person = components['schemas']['Person'];
|
||||||
|
|
||||||
@@ -21,6 +22,6 @@ export function toPersonOption(p: {
|
|||||||
}): PersonOption {
|
}): PersonOption {
|
||||||
return {
|
return {
|
||||||
id: p.id,
|
id: p.id,
|
||||||
displayName: [p.firstName, p.lastName].filter(Boolean).join(' ') || '[Unbekannt]'
|
displayName: joinNameOrUnknown(p.firstName, p.lastName)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user