1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
import type { Choice, Experiment, ExperimentId, Measurement, Parameters, Slider, TestId } from '../experiments';
import { measurementLabel, word, getLanguage, type Language } from '../i18n';
import type { TestLesson } from '../test4';
import { danishLessons, danishTest } from './da';
import type { LessonText, TestCopy } from './lesson-text';
import { narrate } from './narrate';
interface Catalog {
lessons: Record<ExperimentId, LessonText>;
test: (id: TestId) => TestCopy;
narrate: (id: TestId, p: Parameters) => string;
}
const catalogs: Record<Exclude<Language, 'en'>, Catalog> = {
da: { lessons: danishLessons, test: danishTest, narrate },
};
function localizeMeasurements(measurements: Measurement[]): Measurement[] {
return measurements.map(measurement => ({
label: measurementLabel(measurement.label),
value: word(measurement.value),
unit: word(measurement.unit),
}));
}
function localizeControls(experiment: Experiment, lessons: Record<ExperimentId, LessonText>): (Slider | Choice)[] {
const copy = lessons[experiment.id].controls;
return experiment.controls.map(control => {
const text = copy[control.id];
if (!text) return control;
if (control.kind === 'range') return { ...control, label: text.label };
return {
...control,
label: text.label,
options: control.options.map(option => ({ ...option, label: text.options?.[option.value] ?? option.label })),
};
});
}
export function presentLesson<T extends Experiment>(experiment: T): T {
const measure = (p: Parameters) => localizeMeasurements(experiment.measure(p));
const language = getLanguage();
if (language === 'en') return { ...experiment, measure };
const catalog = catalogs[language];
const text = catalog.lessons[experiment.id];
const localized = {
...experiment,
title: text.title,
shortTitle: text.shortTitle,
description: text.description,
explanation: text.explanation,
challenge: text.challenge,
limits: text.limits,
sceneNote: text.sceneNote,
legend: experiment.legend.map(([colour], index) => [colour, text.legend[index] ?? experiment.legend[index][1]] as [string, string]),
source: { ...experiment.source, title: text.sourceTitle },
controls: localizeControls(experiment, catalog.lessons),
equations: text.equations ?? experiment.equations,
measure,
};
if (!('questions' in experiment)) return localized as T;
const lesson = experiment as unknown as TestLesson;
const test = catalog.test(lesson.id);
return {
...localized,
questions: test.questions,
prediction: test.prediction,
predictionAnswer: test.predictionAnswer,
answers: lesson.answers.map((part, index) => ({
...part,
title: test.answers[index].title,
steps: part.steps.map((step, stepIndex) => ({ ...step, why: test.answers[index].steps[stepIndex] })),
})),
observe: (p: Parameters) => catalog.narrate(lesson.id, p),
} as T;
}
|