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([]) }) })