fix(ui): echte Umlaute in allen sichtbaren Texten
Menüs, Dialoge, Schaltflächen, Platzhalter, Hinweise und die
Fehlermeldungen der API standen in Ersatzschreibweise (oe/ae/ue). Sie
erscheinen als Toast oder Beschriftung direkt in der Oberfläche und
gehören damit richtig geschrieben; sechs sichtbare Texte mit ss statt ß
sind gleich mit erledigt ("Schließen", "Straße", "zu groß").
Unangetastet bleibt bewusst:
- Kommentare im Quelltext - die sind durchgängig ASCII, und der Diff wäre
dreimal so groß ohne Nutzen für den Benutzer
- Protokollzeilen (console.*) - die landen im journal, nicht in der App
- Datenbankwerte und interne Kennungen: 'uebernommen', 'empfaenger',
'vorschlaege', 'laeuft-bereits' stecken in Enums, SQL und
Zustandsvergleichen. Ein Umlaut darin hätte still falsche Ergebnisse
geliefert
- server/src/mail/extract.js - die Muster decken absichtlich beide
Schreibweisen ab: /gr(ü|ue)(ß|ss)e/
- scanner/utils/crypto.js - der Ersatzschlüssel darf sich nicht ändern,
sonst sind gespeicherte Portal-Passwörter nicht mehr lesbar
Geprüft mit einem Rundgang durch die Ansichten und Dialoge: sichtbarer
Text plus title/aria-label/placeholder enthalten keine
Ersatzschreibweisen mehr.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ea55acdb5c
commit
8b7ce448a6
@@ -28,7 +28,7 @@ function emptyToNull(value) {
|
||||
function normalizeDate(value) {
|
||||
if (value === null || value === undefined || String(value).trim() === '') return { value: null };
|
||||
const match = /^(\d{4})-(\d{2})-(\d{2})/.exec(String(value).trim());
|
||||
if (!match) return { error: 'Ungueltiges Datum (erwartet JJJJ-MM-TT).' };
|
||||
if (!match) return { error: 'Ungültiges Datum (erwartet JJJJ-MM-TT).' };
|
||||
|
||||
const [, year, month, day] = match;
|
||||
const probe = new Date(Number(year), Number(month) - 1, Number(day));
|
||||
@@ -140,13 +140,13 @@ async function userExists(id) {
|
||||
/** Prueft die Ansprechpartner-Liste `[{ lead_id, role }]`. */
|
||||
async function normalizeContacts(raw) {
|
||||
if (raw === undefined) return undefined;
|
||||
if (!Array.isArray(raw)) return { error: 'Ansprechpartner muessen als Liste uebergeben werden.' };
|
||||
if (!Array.isArray(raw)) return { error: 'Ansprechpartner müssen als Liste übergeben werden.' };
|
||||
|
||||
const seen = new Map();
|
||||
for (const entry of raw) {
|
||||
const leadId = Number(entry?.lead_id ?? entry);
|
||||
if (!Number.isInteger(leadId) || leadId <= 0) {
|
||||
return { error: 'Ungueltige Kontakt-ID bei den Ansprechpartnern.' };
|
||||
return { error: 'Ungültige Kontakt-ID bei den Ansprechpartnern.' };
|
||||
}
|
||||
const role = emptyToNull(entry?.role);
|
||||
if (role !== null && role.length > 120) {
|
||||
@@ -209,7 +209,7 @@ router.post('/', async (req, res, next) => {
|
||||
// etwas anderes gesetzt.
|
||||
const stageGiven = req.body?.stage !== undefined && req.body.stage !== null && req.body.stage !== '';
|
||||
if (stageGiven && !STAGES.has(req.body.stage)) {
|
||||
return res.status(400).json({ error: 'Ungueltige Phase.' });
|
||||
return res.status(400).json({ error: 'Ungültige Phase.' });
|
||||
}
|
||||
const stage = stageGiven ? req.body.stage : 'Neu';
|
||||
|
||||
@@ -241,7 +241,7 @@ router.post('/', async (req, res, next) => {
|
||||
? req.user.id
|
||||
: Number(req.body.owner_id);
|
||||
if (Number.isNaN(ownerId) || !(await userExists(ownerId))) {
|
||||
return res.status(400).json({ error: 'Zustaendiger Benutzer existiert nicht.' });
|
||||
return res.status(400).json({ error: 'Zuständiger Benutzer existiert nicht.' });
|
||||
}
|
||||
|
||||
const contacts = await normalizeContacts(req.body?.contacts ?? []);
|
||||
@@ -289,7 +289,7 @@ router.post('/', async (req, res, next) => {
|
||||
// PATCH /api/opportunities/:id
|
||||
router.patch('/:id', async (req, res, next) => {
|
||||
const id = Number(req.params.id);
|
||||
if (!Number.isInteger(id)) return res.status(400).json({ error: 'Ungueltige Opportunity-ID.' });
|
||||
if (!Number.isInteger(id)) return res.status(400).json({ error: 'Ungültige Opportunity-ID.' });
|
||||
|
||||
const conn = await pool.getConnection();
|
||||
try {
|
||||
@@ -301,7 +301,7 @@ router.patch('/:id', async (req, res, next) => {
|
||||
if (!existing) return res.status(404).json({ error: 'Opportunity nicht gefunden.' });
|
||||
if (!mayModify(req.user, existing)) {
|
||||
return res.status(403).json({
|
||||
error: 'Diese Opportunity darf nur der Ersteller, der Zustaendige oder ein Administrator aendern.',
|
||||
error: 'Diese Opportunity darf nur der Ersteller, der Zuständige oder ein Administrator ändern.',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ router.patch('/:id', async (req, res, next) => {
|
||||
}
|
||||
|
||||
if (req.body?.stage !== undefined) {
|
||||
if (!STAGES.has(req.body.stage)) return res.status(400).json({ error: 'Ungueltige Phase.' });
|
||||
if (!STAGES.has(req.body.stage)) return res.status(400).json({ error: 'Ungültige Phase.' });
|
||||
fields.push('stage = ?');
|
||||
values.push(req.body.stage);
|
||||
}
|
||||
@@ -367,7 +367,7 @@ router.patch('/:id', async (req, res, next) => {
|
||||
const ownerId =
|
||||
req.body.owner_id === null || req.body.owner_id === '' ? null : Number(req.body.owner_id);
|
||||
if (ownerId !== null && (Number.isNaN(ownerId) || !(await userExists(ownerId)))) {
|
||||
return res.status(400).json({ error: 'Zustaendiger Benutzer existiert nicht.' });
|
||||
return res.status(400).json({ error: 'Zuständiger Benutzer existiert nicht.' });
|
||||
}
|
||||
fields.push('owner_id = ?');
|
||||
values.push(ownerId);
|
||||
@@ -377,7 +377,7 @@ router.patch('/:id', async (req, res, next) => {
|
||||
if (contacts?.error) return res.status(400).json({ error: contacts.error });
|
||||
|
||||
if (fields.length === 0 && !contacts) {
|
||||
return res.status(400).json({ error: 'Keine Aenderungen uebergeben.' });
|
||||
return res.status(400).json({ error: 'Keine Änderungen übergeben.' });
|
||||
}
|
||||
|
||||
await conn.beginTransaction();
|
||||
@@ -402,7 +402,7 @@ router.patch('/:id', async (req, res, next) => {
|
||||
// DELETE /api/opportunities/:id - Ansprechpartner raeumt die DB per CASCADE
|
||||
router.delete('/:id', async (req, res, next) => {
|
||||
const id = Number(req.params.id);
|
||||
if (!Number.isInteger(id)) return res.status(400).json({ error: 'Ungueltige Opportunity-ID.' });
|
||||
if (!Number.isInteger(id)) return res.status(400).json({ error: 'Ungültige Opportunity-ID.' });
|
||||
|
||||
try {
|
||||
const [rows] = await pool.query(
|
||||
@@ -413,7 +413,7 @@ router.delete('/:id', async (req, res, next) => {
|
||||
if (!existing) return res.status(404).json({ error: 'Opportunity nicht gefunden.' });
|
||||
if (!mayModify(req.user, existing)) {
|
||||
return res.status(403).json({
|
||||
error: 'Diese Opportunity darf nur der Ersteller, der Zustaendige oder ein Administrator loeschen.',
|
||||
error: 'Diese Opportunity darf nur der Ersteller, der Zuständige oder ein Administrator löschen.',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user