- Texte stehen nur noch in remotion/src/folge02/texte/<sprache>.json, die Szenen enthalten nur Ablauf und Bewegung - Sprache beim Rendern wählbar (render.mjs --sprache es, Studio über --props); Zeitplan richtet sich nach Textlänge bzw. Aufnahmen der Sprache - Baukasten-Wörter je Sprache in baukasten/sprache.ts: Kanalname im Buch (mit festem Umbruch für ES/FR), „Heute: …“, Sprechernamen, Kalendertitel, „Hatschi!“; Kalenderbild für ES/FR vorberechnet - Stimmen je Sprache: stimmen/<sprache>.json, public/stimmen/folge02/<sprache>/, stimmen.mts --sprache, eigene Stimmen je Sprache möglich - neues werkzeuge/texte.mts: prüft fehlende Übersetzungen, --tabelle zum Gegenlesen - README, CLAUDE.md und Drehbuch-Hinweise angepasst Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
69 lines
3.2 KiB
TypeScript
69 lines
3.2 KiB
TypeScript
// Prüft die Sprechtexte einer Folge (src/folgeNN/texte/<sprache>.json):
|
|
// Fehlt in einer Sprache eine Zeile, die eine Szene braucht, oder steht dort
|
|
// eine, die keine Szene mehr benutzt?
|
|
//
|
|
// npx tsx werkzeuge/texte.mts F02 prüfen
|
|
// npx tsx werkzeuge/texte.mts F02 --tabelle alle Sprachen nebeneinander (Markdown)
|
|
//
|
|
// Kostet nichts und ändert nichts.
|
|
|
|
import {spawnSync} from 'node:child_process';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import {fileURLToPath} from 'node:url';
|
|
|
|
const WURZEL = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
process.chdir(WURZEL);
|
|
|
|
const args = process.argv.slice(2);
|
|
const kuerzel = args.find((a) => !a.startsWith('--'));
|
|
if (!kuerzel) throw new Error('Folge angeben, z. B. F02');
|
|
const nummer = kuerzel.replace(/\D/g, '');
|
|
const SPRACHEN = ['de', 'es', 'fr'];
|
|
|
|
type Texte = {titel: string; lied?: string; zeilen: Record<string, string>};
|
|
const texte: Record<string, Texte> = Object.fromEntries(
|
|
SPRACHEN.map((s) => [s, JSON.parse(fs.readFileSync(`src/folge${nummer}/texte/${s}.json`, 'utf8')) as Texte]),
|
|
);
|
|
|
|
// Welche Zeilen sprechen die Szenen? (Zeilen, die der Baukasten selbst
|
|
// mitbringt, z. B. das Intro, stehen nicht in den Textdateien.)
|
|
const npx = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
const ausgabe = spawnSync(npx, ['tsx', 'werkzeuge/szenenliste.mts', `./src/folge${nummer}/Folge${nummer}.tsx`, kuerzel], {
|
|
encoding: 'utf8',
|
|
shell: process.platform === 'win32',
|
|
env: {...process.env, SPRACHE: 'de'},
|
|
});
|
|
const szenen = JSON.parse(ausgabe.stdout.split('\n').filter((z) => z.startsWith('[')).pop()!) as {szene?: string; zeilen: {id: string; wer?: string; text: string}[]}[];
|
|
const gebraucht: {schl: string; wer?: string}[] = [];
|
|
for (const s of szenen) {
|
|
if (!s.szene) continue;
|
|
for (const z of s.zeilen) {
|
|
const schl = `${s.szene}/${z.id}`;
|
|
if (schl in texte.de.zeilen || z.text.startsWith('[fehlt:')) gebraucht.push({schl, wer: z.wer});
|
|
}
|
|
}
|
|
|
|
if (args.includes('--tabelle')) {
|
|
const zelle = (t?: string) => (t ?? '**fehlt**').replaceAll('|', '\\|');
|
|
console.log(`| Zeile | Wer | ${SPRACHEN.join(' | ')} |`);
|
|
console.log(`| --- | --- | ${SPRACHEN.map(() => '---').join(' | ')} |`);
|
|
console.log(`| Titel | | ${SPRACHEN.map((s) => zelle(texte[s].titel)).join(' | ')} |`);
|
|
for (const g of gebraucht) console.log(`| ${g.schl} | ${g.wer ?? ''} | ${SPRACHEN.map((s) => zelle(texte[s].zeilen[g.schl])).join(' | ')} |`);
|
|
process.exit(0);
|
|
}
|
|
|
|
let fehler = 0;
|
|
const schluessel = new Set(gebraucht.map((g) => g.schl));
|
|
for (const s of SPRACHEN) {
|
|
const fehlt = gebraucht.filter((g) => !(g.schl in texte[s].zeilen)).map((g) => g.schl);
|
|
const uebrig = Object.keys(texte[s].zeilen).filter((k) => !schluessel.has(k));
|
|
const leer = Object.entries(texte[s].zeilen).filter(([, t]) => !t.trim()).map(([k]) => k);
|
|
if (!texte[s].titel) fehlt.unshift('titel');
|
|
for (const k of fehlt) console.log(`✗ ${s}: fehlt ${k}`);
|
|
for (const k of leer) console.log(`✗ ${s}: leer ${k}`);
|
|
for (const k of uebrig) console.log(`? ${s}: nicht benutzt ${k}`);
|
|
fehler += fehlt.length + leer.length;
|
|
if (!fehlt.length && !leer.length && !uebrig.length) console.log(`✓ ${s}: ${Object.keys(texte[s].zeilen).length} Zeilen`);
|
|
}
|
|
process.exit(fehler ? 1 : 0);
|