Files
AfiS-Aktensystem/web/tests/i18n.test.ts
T
Harlekin c6401aeb4d Rollenstruktur und englische Fachbegriffe festgelegt
Der Discord-Server hat drei Sorten Rollen, die Dokumente kannten nur eine:
Zugehörigkeit (AfiS, Personalabteilung) als Türsteher, Rangrollen für die
Rechte, Zugangsrollen für die Freigabestufe. Das bestehende RoleMapping trägt
das fast, es fehlt nur der Türsteher. Die beiden Felder dafür kommen mit
Phase 1, die Struktur ist in docs/13-entscheidungen.md festgehalten.

Die Freigabestufen heißen jetzt wie die Zugangsrollen: Unclassified,
Restricted Access, Confidential Access, Sensitive Access, Critical Operations,
Executive Oversight. Fachbegriffe der Domäne bleiben englisch, auch in einer
deutschen Oberfläche.

Die Bezeichnungen sind damit Daten in ClearanceLevelConfig, nicht mehr
Oberflächentext in lib/i18n/de.ts: sie sind im Adminbereich änderbar, und was
der Leiter ändern kann, gehört nicht in eine Übersetzungsdatei. StampMark
bekommt den Namen hereingereicht.

Vier neue Tests prüfen den Zustand, den der Seed herstellt, gegen die
Datenbank statt gegen eine Konstante im Code.
2026-09-01 18:50:07 +02:00

47 lines
1.7 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { readFileSync, readdirSync, statSync } from 'node:fs'
import { join } from 'node:path'
import { de } from '@/lib/i18n/de'
describe('Sprachkonvention', () => {
it('haelt die Stufenbezeichnungen aus den Texten heraus', () => {
// Sie stehen in ClearanceLevelConfig, sind im Adminbereich aenderbar und
// folgen den Zugangsrollen des Discord-Servers.
expect(de.clearance).not.toHaveProperty('names')
})
it('verzichtet auf Ausrufezeichen und Entschuldigungen', () => {
const flat = JSON.stringify(de)
expect(flat).not.toMatch(/!/)
expect(flat.toLowerCase()).not.toMatch(/erfolgreich|entschuldigung/)
})
it('haelt deutsche Oberflaechentexte aus dem JSX heraus', () => {
// Umlaute und Eszett sind der billigste verlaessliche Marker fuer einen
// deutschen Text. Alles Sichtbare gehoert nach lib/i18n/de.ts, siehe CLAUDE.md.
const offenders: string[] = []
const roots = ['app', 'components']
function walk(dir: string) {
for (const name of readdirSync(dir)) {
const path = join(dir, name)
if (statSync(path).isDirectory()) {
walk(path)
continue
}
if (!name.endsWith('.tsx')) continue
const source = readFileSync(path, 'utf8')
for (const [index, line] of source.split('\n').entries()) {
const withoutComments = line.replace(/\/\/.*$/, '').replace(/\/\*.*?\*\//g, '')
if (/[äöüÄÖÜß]/.test(withoutComments)) {
offenders.push(`${path}:${index + 1}`)
}
}
}
}
for (const root of roots) walk(join(process.cwd(), root))
expect(offenders).toEqual([])
})
})