Files
AirCardIOS/web/src/i18n/api-messages.ts
T
ClaudeandClaude Opus 5.5 3051b3b3f9 feat(logos): Datenschicht, API-Aufrufe und übersetzbare API-Fehler
- logos/logos.ts (Muster community/gallery.ts): CommunityLogo, toLogo, logoQueries (Beliebt/Neu, Admin-Filter Gemeldet und
  Ausgeblendet, Cursor), listLogos (nextCursor nur bei voller Seite von 24), getLogo (ungültige ID oder 404 -> null),
  myHearts (eigene Herzen einer Seite, ohne IDs keine Anfrage), listLogoReports (ohne Melder-Hash), loadLogoBlob.
- logos/logo-api.ts: uploadLogo, setHeart, reportLogo (ohne Anmeldung), deleteLogo, setLogoVisibility über apiPost.
  uploadLogo behandelt das Limit (429 tooManyLogos) wie publishCard als eindeutige Ablehnung (die hochgeladene Datei darf
  aufgeräumt werden); eine Antwort ohne id (und bei setHeart ohne Zustand und Zähler) ist 503 mit offenem Ausgang.
- account/appwrite.ts: IDS um logos, logoLikes, logoReports und logoBucket.
- community/api.ts: ApiError.serverCode (der Schlüssel aus {error, code}; code bleibt der HTTP-Status, message der deutsche
  Text). Client-Fehler tragen unavailable (auch 502/503/504 vom Proxy, vor dem Lesen des Bodys), generic, jwtUnsupported,
  alreadyPublished, tooManyPublications. Neu: unavailableError() und apiErrorText(err). Die deutschen Texte stehen einmal
  in api-messages.ts, die Vergleiche in publishCard laufen unverändert über err.message.
- i18n/api-messages.ts: API_MESSAGES (alle 33 Texte von MSG plus die Client-Codes generic und jwtUnsupported) und
  apiMessage: bekannter Code -> t(Text); unbekannt: Deutsch der Servertext, Englisch eine Meldung je Status (400, 403, 404,
  sonst allgemein). Der Code badRequest trägt auch die dynamischen Prüftexte des Dienstes, Deutsch zeigt dann den
  genaueren Servertext.
- i18n/en.ts: englische Texte zu allen API_MESSAGES.
- Tests: api-messages.test.ts lädt MSG aus deploy/api/common.js (createRequire) und prüft den Gleichlauf in beide
  Richtungen; logos.test.ts, logo-api.test.ts und neue Fälle in api.test.ts (der Helfer freshApi stellt die frische
  i18n-Instanz auf Deutsch). 156 neue Tests, die bisherigen unverändert grün (1285 gesamt).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 19:59:08 +00:00

70 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Übersetzbare Fehlertexte der API: Der Dienst `aircard-api` (deploy/api) antwortet auf Fehler mit `{error, code}`. `error` ist der
// deutsche Text, `code` sein Schlüssel in MSG (deploy/api/common.js). Hier steht jeder Text noch einmal unter seinem Schlüssel
// (der Browser lädt den Dienst nicht); api-messages.test.ts lädt MSG und prüft den Gleichlauf. Dazu kommen zwei Client-Codes.
// Übersetzt wird beim Anzeigen (`apiMessage`); `ApiError.message` bleibt der deutsche Text, damit Vergleiche damit weiter gehen.
import { currentLang, msg, t } from './i18n';
export const API_MESSAGES: Readonly<Record<string, string>> = {
// Die Schlüssel und Texte von MSG, in derselben Reihenfolge.
unauthorized: msg('Bitte melde dich an.'),
notFound: msg('Nicht gefunden.'),
cardGone: msg('Diese Karte ist nicht (mehr) verfügbar.'),
forbidden: msg('Dazu hast du keine Berechtigung.'),
adminOnly: msg('Nur für Admins.'),
foreignFile: msg('Diese Datei gehört dir nicht.'),
fileMissing: msg('Bild nicht gefunden.'),
fileType: msg('Das Bild muss eine PNG- oder WebP-Datei sein.'),
fileSize: msg('Das Bild ist größer als 5 MB.'),
alreadyPublished: msg('Diese Karte ist schon veröffentlicht.'),
filesTaken: msg('Diese Bilder sind bereits veröffentlicht oder gesperrt.'),
imageFormat: msg('Das Bild hat nicht das Kartenformat.'),
notYourCard: msg('Diese Karte gehört nicht zu deinem Konto.'),
tooManyPublications: msg('Du hast schon 20 Karten veröffentlicht. Zieh eine zurück, um eine neue zu veröffentlichen.'),
tooManyReports: msg('Zu viele Meldungen – bitte später nochmal.'),
badRequest: msg('Ungültige Anfrage.'),
badCardId: msg('Ungültige Karten-ID.'),
badReason: msg('Bitte wähle einen gültigen Grund.'),
badVisibility: msg('Ungültige Angabe zur Sichtbarkeit.'),
logoGone: msg('Dieses Logo ist nicht (mehr) verfügbar.'),
badLogoId: msg('Ungültige Logo-ID.'),
logoNameMissing: msg('Bitte gib einen Namen an.'),
logoFileType: msg('Das Logo muss eine PNG-Datei sein.'),
logoFileSize: msg('Das Logo ist größer als 1 MB.'),
logoFormat: msg('Das Logo hat ungültige Maße (8 × 8 bis 720 × 250 Pixel).'),
logoTaken: msg('Diese Datei wird schon für ein Logo verwendet.'),
tooManyLogos: msg('Du hast schon 30 Logos hochgeladen. Lösche eins, um ein neues hochzuladen.'),
badHeart: msg('Ungültige Angabe zum Herz.'),
badMono: msg('Ungültige Angabe zu „einfarbig“.'),
tooLarge: msg('Die Anfrage ist zu groß.'),
jsonOnly: msg('Nur application/json wird unterstützt.'),
unavailable: msg('Der Dienst ist gerade nicht erreichbar.'),
internal: msg('Interner Fehler.'),
// Nur im Client (kein Schlüssel im Dienst): allgemeiner Fehler und „Anmeldung per Token ausgeschaltet“.
generic: msg('Etwas ist schiefgelaufen. Bitte nochmal versuchen.'),
jwtUnsupported: msg('Anmeldung per Token ist auf dem Server ausgeschaltet – bitte den Betreiber informieren.'),
};
/** Die allgemeine Meldung zu einem Status, wenn der Code unbekannt ist (Spec § 7): 400, 403, 404, sonst „Etwas ist schiefgelaufen“. */
function fallbackText(status: number): string {
if (status === 400) return API_MESSAGES.badRequest;
if (status === 403) return API_MESSAGES.forbidden;
if (status === 404) return API_MESSAGES.notFound;
return API_MESSAGES.generic;
}
/**
* Der Text zu einem Fehler des Dienstes (oder einem Fehler, den der Client mit denselben Codes erzeugt) in der Sprache der Seite.
* Ein bekannter Code wird über das Wörterbuch übersetzt. Ein unbekannter oder fehlender Code (älterer Dienst, Proxy) zeigt auf
* Deutsch den Text des Dienstes, auf Englisch eine allgemeine Meldung je Status.
*/
export function apiMessage(serverCode: string | null, status: number, serverText: string): string {
const english = currentLang() === 'en';
if (serverCode !== null && Object.hasOwn(API_MESSAGES, serverCode)) {
// `badRequest` tragen auch die dynamischen Prüftexte des Dienstes („Der Titel ist zu lang (höchstens 60 Zeichen).“):
// Deutsch zeigt dann den genaueren Servertext, Englisch den allgemeinen Text des Codes.
if (!english && serverCode === 'badRequest') return serverText;
return t(API_MESSAGES[serverCode]);
}
return english ? t(fallbackText(status)) : serverText;
}