Swedish adaptation: Instegscertifikat and HAREC
- Editions replaced by INSTEG, HAREC and UPPGRADERING (Instegscertifikat -> HAREC) - Question pool optional; simulator, homework tool and solutions switch off without one - All UI strings, templates, renderers and project JS localised to sv-SE (decimal comma, Swedish non-breaking-space rules, Å/Ä/Ö in Morse table) - DARC branding, membership CTA and German links removed; attribution footer added - Page names centralised in src/pages.py - README and docs rewritten in Swedish Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
+60
-84
@@ -6,27 +6,28 @@
|
||||
var QUESTION_COUNT = 25;
|
||||
var ANSWER_LABELS = ["A", "B", "C", "D"];
|
||||
|
||||
// TODO: Adapt exam parts and passing thresholds once a Swedish question pool exists.
|
||||
var PART_DEFINITIONS = {
|
||||
B: { label: "Betriebliche Kenntnisse", minutes: 45 },
|
||||
V: { label: "Kenntnisse von Vorschriften", minutes: 45 },
|
||||
N: { label: "Technische Kenntnisse Klasse N", minutes: 45 },
|
||||
E: { label: "Technische Kenntnisse Klasse E", minutes: 45 },
|
||||
A: { label: "Technische Kenntnisse Klasse A", minutes: 60 },
|
||||
H: { label: "Hausaufgabe", minutes: null }
|
||||
B: { label: "Operativa kunskaper", minutes: 45 },
|
||||
V: { label: "Kunskaper om föreskrifter", minutes: 45 },
|
||||
N: { label: "Tekniska kunskaper, nivå N", minutes: 45 },
|
||||
E: { label: "Tekniska kunskaper, nivå E", minutes: 45 },
|
||||
A: { label: "Tekniska kunskaper, nivå A", minutes: 60 },
|
||||
H: { label: "Övning", minutes: null }
|
||||
};
|
||||
|
||||
var EXAM_CHOICES = [
|
||||
{ id: "N", group: "primary", label: "Klasse N", detail: "B + V + N", parts: ["B", "V", "N"], color: "#47ABE8" },
|
||||
{ id: "E", group: "primary", label: "Klasse E", detail: "B + V + N + E", parts: ["B", "V", "N", "E"], color: "#FE756C" },
|
||||
{ id: "A", group: "primary", label: "Klasse A", detail: "B + V + N + E + A", parts: ["B", "V", "N", "E", "A"], color: "#3BB583" },
|
||||
{ id: "N-E", group: "upgrade", label: "N → E", detail: "Technik E", parts: ["E"], color: "#FE756C" },
|
||||
{ id: "N-A", group: "upgrade", label: "N → A", detail: "Technik E + A", parts: ["E", "A"], color: "#3BB583" },
|
||||
{ id: "E-A", group: "upgrade", label: "E → A", detail: "Technik A", parts: ["A"], color: "#3BB583" },
|
||||
{ id: "part-B", group: "single", label: "B", detail: "Betriebliche Kenntnisse", parts: ["B"], color: "#47ABE8" },
|
||||
{ id: "part-V", group: "single", label: "V", detail: "Kenntnisse von Vorschriften", parts: ["V"], color: "#47ABE8" },
|
||||
{ id: "part-N", group: "single", label: "N", detail: "Technik Klasse N", parts: ["N"], color: "#47ABE8" },
|
||||
{ id: "part-E", group: "single", label: "E", detail: "Technik Klasse E", parts: ["E"], color: "#FE756C" },
|
||||
{ id: "part-A", group: "single", label: "A", detail: "Technik Klasse A", parts: ["A"], color: "#3BB583" }
|
||||
{ id: "N", group: "primary", label: "Nivå N", detail: "B + V + N", parts: ["B", "V", "N"], color: "#47ABE8" },
|
||||
{ id: "E", group: "primary", label: "Nivå E", detail: "B + V + N + E", parts: ["B", "V", "N", "E"], color: "#FE756C" },
|
||||
{ id: "A", group: "primary", label: "Nivå A", detail: "B + V + N + E + A", parts: ["B", "V", "N", "E", "A"], color: "#3BB583" },
|
||||
{ id: "N-E", group: "upgrade", label: "N → E", detail: "Teknik E", parts: ["E"], color: "#FE756C" },
|
||||
{ id: "N-A", group: "upgrade", label: "N → A", detail: "Teknik E + A", parts: ["E", "A"], color: "#3BB583" },
|
||||
{ id: "E-A", group: "upgrade", label: "E → A", detail: "Teknik A", parts: ["A"], color: "#3BB583" },
|
||||
{ id: "part-B", group: "single", label: "B", detail: "Operativa kunskaper", parts: ["B"], color: "#47ABE8" },
|
||||
{ id: "part-V", group: "single", label: "V", detail: "Kunskaper om föreskrifter", parts: ["V"], color: "#47ABE8" },
|
||||
{ id: "part-N", group: "single", label: "N", detail: "Teknik nivå N", parts: ["N"], color: "#47ABE8" },
|
||||
{ id: "part-E", group: "single", label: "E", detail: "Teknik nivå E", parts: ["E"], color: "#FE756C" },
|
||||
{ id: "part-A", group: "single", label: "A", detail: "Teknik nivå A", parts: ["A"], color: "#3BB583" }
|
||||
];
|
||||
|
||||
function queryValue(name) {
|
||||
@@ -72,7 +73,7 @@
|
||||
input.select();
|
||||
var copied = document.execCommand("copy");
|
||||
input.remove();
|
||||
return copied ? Promise.resolve() : Promise.reject(new Error("Kopieren nicht möglich"));
|
||||
return copied ? Promise.resolve() : Promise.reject(new Error("Det gick inte att kopiera"));
|
||||
}
|
||||
|
||||
function shuffled(values) {
|
||||
@@ -149,7 +150,7 @@
|
||||
|
||||
function balancedSample(pool, count) {
|
||||
if (!Array.isArray(pool) || pool.length < count) {
|
||||
throw new Error("Für diesen Prüfungsteil stehen nicht genügend Fragen zur Verfügung.");
|
||||
throw new Error("Det finns inte tillräckligt många frågor för den här provdelen.");
|
||||
}
|
||||
return pickFromTree(buildCategoryTree(pool), count);
|
||||
}
|
||||
@@ -196,7 +197,7 @@
|
||||
var currentChoice = computed(function () {
|
||||
if (!session.value) return null;
|
||||
if (session.value.mode === "homework") {
|
||||
return { id: "H", label: "Hausaufgabe", parts: ["H"] };
|
||||
return { id: "H", label: "Övning", parts: ["H"] };
|
||||
}
|
||||
return EXAM_CHOICES.find(function (choice) { return choice.id === session.value.choiceId; });
|
||||
});
|
||||
@@ -256,17 +257,17 @@
|
||||
return { homework: "task_alt", passed: "verified", oral: "record_voice_over", failed: "cancel", incomplete: "stop_circle" }[overallState.value];
|
||||
});
|
||||
var overallTitle = computed(function () {
|
||||
return { homework: "Hausaufgabe ausgewertet", passed: "Prüfung bestanden", oral: "Mündliche Nachprüfung möglich", failed: "Prüfung nicht bestanden", incomplete: "Prüfung vorzeitig beendet" }[overallState.value];
|
||||
return { homework: "Övningen är rättad", passed: "Provet godkänt", oral: "Muntlig komplettering möjlig", failed: "Provet inte godkänt", incomplete: "Provet avslutades i förtid" }[overallState.value];
|
||||
});
|
||||
var overallText = computed(function () {
|
||||
if (overallState.value === "homework") {
|
||||
var homeworkPart = session.value.parts[0];
|
||||
return homeworkPart.score + " von " + homeworkPart.questions.length + " Fragen wurden richtig beantwortet.";
|
||||
return homeworkPart.score + " av " + homeworkPart.questions.length + " frågor besvarades rätt.";
|
||||
}
|
||||
if (overallState.value === "passed") return "Gratulation! Du hast jeden Prüfungsteil mit mindestens 19 Punkten bestanden.";
|
||||
if (overallState.value === "oral") return "In genau einem Prüfungsteil wurden 17 oder 18 Punkte erreicht; nach den Prüfungsregeln kann eine mündliche Nachprüfung möglich sein.";
|
||||
if (overallState.value === "failed") return "Mindestens ein Prüfungsteil wurde nicht bestanden.";
|
||||
return evaluatedParts().length + " von " + session.value.parts.length + " Prüfungsteilen wurden abgeschlossen.";
|
||||
if (overallState.value === "passed") return "Grattis! Du har klarat varje provdel med minst 19 poäng.";
|
||||
if (overallState.value === "oral") return "I exakt en provdel nåddes 17 eller 18 poäng; enligt provreglerna kan en muntlig komplettering vara möjlig.";
|
||||
if (overallState.value === "failed") return "Minst en provdel är inte godkänd.";
|
||||
return evaluatedParts().length + " av " + session.value.parts.length + " provdelar har slutförts.";
|
||||
});
|
||||
|
||||
function questionData(questionState) {
|
||||
@@ -331,9 +332,9 @@
|
||||
function createHomeworkPart(questionIds) {
|
||||
var questions = questionIds.map(function (questionId) { return catalog.value[questionId]; }).filter(Boolean);
|
||||
if (questions.length !== questionIds.length) {
|
||||
throw new Error("Mindestens eine Frage aus dem Hausaufgabenlink ist nicht im aktuellen Fragenkatalog enthalten.");
|
||||
throw new Error("Minst en fråga i övningslänken finns inte i den aktuella frågebanken.");
|
||||
}
|
||||
if (questions.length === 0) throw new Error("Der Hausaufgabenlink enthält keine gültigen Fragen.");
|
||||
if (questions.length === 0) throw new Error("Övningslänken innehåller inga giltiga frågor.");
|
||||
return {
|
||||
code: "H",
|
||||
status: "pending",
|
||||
@@ -481,8 +482,8 @@
|
||||
function requestSubmit() {
|
||||
var unanswered = currentQuestionCount.value - answeredCount.value;
|
||||
var text = unanswered > 0
|
||||
? "Du hast " + unanswered + " Fragen nicht beantwortet. Möchtest du " + (isHomework.value ? "die Hausaufgabe" : "den Prüfungsteil") + " trotzdem abgeben?"
|
||||
: "Möchtest du " + (isHomework.value ? "die Hausaufgabe" : "diesen Prüfungsteil") + " jetzt verbindlich abgeben?";
|
||||
? "Du har inte besvarat " + unanswered + " frågor. Vill du lämna in " + (isHomework.value ? "övningen" : "provdelen") + " ändå?"
|
||||
: "Vill du lämna in " + (isHomework.value ? "övningen" : "den här provdelen") + " nu? Det går inte att ångra.";
|
||||
if (window.confirm(text)) submitPart(false);
|
||||
}
|
||||
|
||||
@@ -502,7 +503,7 @@
|
||||
}
|
||||
|
||||
function finishExamEarly() {
|
||||
if (!window.confirm("Möchtest du die Prüfung wirklich hier beenden? Nicht bearbeitete Teile gelten dann als nicht abgeschlossen.")) return;
|
||||
if (!window.confirm("Vill du verkligen avsluta provet här? Delar som inte har gjorts räknas som ej slutförda.")) return;
|
||||
showSummary();
|
||||
}
|
||||
|
||||
@@ -540,22 +541,22 @@
|
||||
}
|
||||
|
||||
function abortExam() {
|
||||
var noun = isHomework.value ? "Hausaufgabe" : "Simulation";
|
||||
if (!window.confirm("Möchtest du diese " + noun + " abbrechen? Der gespeicherte Stand wird gelöscht.")) return;
|
||||
var noun = isHomework.value ? "övningen" : "simuleringen";
|
||||
if (!window.confirm("Vill du avbryta " + noun + "? Det sparade läget raderas.")) return;
|
||||
resetExam();
|
||||
window.history.replaceState(null, "", "simulation.html");
|
||||
window.history.replaceState(null, "", "simulering.html");
|
||||
}
|
||||
|
||||
function newExam() {
|
||||
resetExam();
|
||||
window.history.replaceState(null, "", "simulation.html");
|
||||
window.history.replaceState(null, "", "simulering.html");
|
||||
}
|
||||
|
||||
function retryHomework() {
|
||||
var questionIds = session.value && session.value.homeworkIds;
|
||||
if (!questionIds) return;
|
||||
clearStoredSession();
|
||||
var homeworkUrl = new URL("simulation.html", window.location.href);
|
||||
var homeworkUrl = new URL("simulering.html", window.location.href);
|
||||
homeworkUrl.search = "?homework=" + questionIds.join("+");
|
||||
window.history.replaceState(null, "", homeworkUrl.toString());
|
||||
startHomework(questionIds);
|
||||
@@ -568,10 +569,10 @@
|
||||
}
|
||||
|
||||
function resultLabel(part) {
|
||||
if (part.code === "H") return "Ausgewertet";
|
||||
if (part.score >= 19) return "Bestanden";
|
||||
if (part.score >= 17) return "Nachprüfung möglich";
|
||||
return "Nicht bestanden";
|
||||
if (part.code === "H") return "Rättad";
|
||||
if (part.score >= 19) return "Godkänd";
|
||||
if (part.score >= 17) return "Komplettering möjlig";
|
||||
return "Inte godkänd";
|
||||
}
|
||||
|
||||
function resultAlertClass(part) {
|
||||
@@ -596,11 +597,11 @@
|
||||
}
|
||||
|
||||
function resultDescription(part) {
|
||||
if (part.code === "H") return part.score + " von " + part.questions.length + " Fragen wurden richtig beantwortet.";
|
||||
var prefix = part.autoSubmitted ? "Die Zeit ist abgelaufen und der Prüfungsteil wurde automatisch abgegeben. " : "";
|
||||
if (part.score >= 19) return prefix + "Die erforderlichen 19 Punkte wurden erreicht.";
|
||||
if (part.score >= 17) return prefix + "Mit 17 oder 18 Punkten kann nach den Prüfungsregeln eine mündliche Nachprüfung möglich sein.";
|
||||
return prefix + "Die erforderlichen 19 Punkte wurden nicht erreicht.";
|
||||
if (part.code === "H") return part.score + " av " + part.questions.length + " frågor besvarades rätt.";
|
||||
var prefix = part.autoSubmitted ? "Tiden gick ut och provdelen lämnades in automatiskt. " : "";
|
||||
if (part.score >= 19) return prefix + "De nödvändiga 19 poängen uppnåddes.";
|
||||
if (part.score >= 17) return prefix + "Med 17 eller 18 poäng kan en muntlig komplettering vara möjlig enligt provreglerna.";
|
||||
return prefix + "De nödvändiga 19 poängen uppnåddes inte.";
|
||||
}
|
||||
|
||||
function encodedResult(result) {
|
||||
@@ -608,30 +609,6 @@
|
||||
return "1." + result.choice.id + "." + result.scores.join(".");
|
||||
}
|
||||
|
||||
function resultImageCode(result) {
|
||||
if (!result) return "";
|
||||
if (result.kind === "homework") return result.score === result.total ? "aenbv" : "";
|
||||
if (!result.passed) return "";
|
||||
var order = ["A", "E", "N", "B", "V"];
|
||||
return order.filter(function (part) {
|
||||
return result.choice.parts.indexOf(part) !== -1;
|
||||
}).join("").toLowerCase();
|
||||
}
|
||||
|
||||
function shareableSessionResult() {
|
||||
if (!session.value) return null;
|
||||
if (isHomework.value) {
|
||||
return { kind: "homework", score: session.value.parts[0].score, total: session.value.parts[0].questions.length };
|
||||
}
|
||||
if (session.value.parts.some(function (part) { return part.status !== "evaluated"; })) return null;
|
||||
return {
|
||||
kind: "exam",
|
||||
choice: currentChoice.value,
|
||||
scores: session.value.parts.map(function (part) { return part.score; }),
|
||||
passed: overallState.value === "passed"
|
||||
};
|
||||
}
|
||||
|
||||
var resultForSharing = computed(function () {
|
||||
if (sharedResult.value) return sharedResult.value;
|
||||
if (view.value !== "summary") return null;
|
||||
@@ -640,8 +617,7 @@
|
||||
|
||||
function buildResultUrl(result) {
|
||||
if (!result) return "";
|
||||
var imageCode = resultImageCode(result);
|
||||
var url = new URL(imageCode ? "result-" + imageCode + ".html" : "result.html", window.location.href);
|
||||
var url = new URL("resultat.html", window.location.href);
|
||||
url.search = "?result=" + encodedResult(result);
|
||||
return url.toString();
|
||||
}
|
||||
@@ -654,19 +630,19 @@
|
||||
return buildResultUrl(resultForSharing.value);
|
||||
});
|
||||
|
||||
// There are no result images for sharing.
|
||||
var resultImageUrl = computed(function () {
|
||||
var imageCode = resultImageCode(resultForSharing.value);
|
||||
return imageCode ? "assets/images/exam-" + imageCode + ".jpeg" : "";
|
||||
return "";
|
||||
});
|
||||
|
||||
var shareText = computed(function () {
|
||||
var result = resultForSharing.value;
|
||||
if (!result) return "";
|
||||
if (result.kind === "homework") {
|
||||
return "Meine 50ohm.de-Hausaufgabe: " + result.score + " von " + result.total + " Fragen richtig.";
|
||||
return "Min övning på 50Ω: " + result.score + " av " + result.total + " frågor rätt.";
|
||||
}
|
||||
var scores = result.choice.parts.map(function (part, index) { return part + ": " + result.scores[index] + "/25"; }).join(", ");
|
||||
return "Meine 50ohm.de-Prüfungssimulation " + result.choice.label + ": " + scores + " – " + (result.passed ? "bestanden!" : "noch nicht bestanden.");
|
||||
return "Min provsimulering på 50Ω " + result.choice.label + ": " + scores + " – " + (result.passed ? "godkänd!" : "ännu inte godkänd.");
|
||||
});
|
||||
|
||||
var socialShareLinks = computed(function () {
|
||||
@@ -681,8 +657,8 @@
|
||||
|
||||
function copyResultLink() {
|
||||
copyText(resultShareUrl.value)
|
||||
.then(function () { shareMessage.value = "Ergebnislink kopiert."; })
|
||||
.catch(function () { shareMessage.value = "Der Link konnte nicht automatisch kopiert werden."; });
|
||||
.then(function () { shareMessage.value = "Resultatlänken kopierades."; })
|
||||
.catch(function () { shareMessage.value = "Länken kunde inte kopieras automatiskt."; });
|
||||
}
|
||||
|
||||
function shareNative() {
|
||||
@@ -690,7 +666,7 @@
|
||||
copyResultLink();
|
||||
return;
|
||||
}
|
||||
navigator.share({ title: "50ohm.de-Ergebnis", text: shareText.value, url: resultShareUrl.value }).catch(function () {});
|
||||
navigator.share({ title: "Resultat från 50Ω", text: shareText.value, url: resultShareUrl.value }).catch(function () {});
|
||||
}
|
||||
|
||||
function restoreSession(homeworkQuestionIds, allowHomeworkResult) {
|
||||
@@ -758,24 +734,24 @@
|
||||
|
||||
function loadCatalog() {
|
||||
Promise.all([
|
||||
fetch("assets/fragenkatalog.json"),
|
||||
fetch("assets/question_pool.json"),
|
||||
fetch("assets/metadata.json"),
|
||||
fetch("assets/question_index.json")
|
||||
])
|
||||
.then(function (responses) {
|
||||
var names = ["Fragenkatalog", "Metadaten", "Fragenindex"];
|
||||
var names = ["Frågebanken", "Metadata", "Frågeindex"];
|
||||
responses.forEach(function (response, index) {
|
||||
if (!response.ok) throw new Error(names[index] + " nicht gefunden (HTTP " + response.status + ").");
|
||||
if (!response.ok) throw new Error(names[index] + " hittades inte (HTTP " + response.status + ").");
|
||||
});
|
||||
return Promise.all(responses.map(function (response) { return response.json(); }));
|
||||
})
|
||||
.then(function (data) {
|
||||
catalog.value = window.FiftyOhmQuestions.normalizeCatalog(data[0], data[1] || {}, data[2] || {});
|
||||
if (Object.keys(catalog.value).length === 0) throw new Error("Der Fragenkatalog ist leer.");
|
||||
if (Object.keys(catalog.value).length === 0) throw new Error("Frågebanken är tom.");
|
||||
var parsedResult = parseSharedResult();
|
||||
var homeworkQuestionIds = parseHomeworkQuestionIds();
|
||||
if (queryValue("result")) {
|
||||
if (!parsedResult) throw new Error("Der Ergebnislink ist ungültig.");
|
||||
if (!parsedResult) throw new Error("Resultatlänken är ogiltig.");
|
||||
restoreSession([], true);
|
||||
var storedResult = shareableSessionResult();
|
||||
if (storedResult && encodedResult(storedResult) === queryValue("result")) {
|
||||
@@ -794,7 +770,7 @@
|
||||
renderMathSoon(Vue);
|
||||
})
|
||||
.catch(function (error) {
|
||||
loadError.value = error.message || "Unbekannter Ladefehler";
|
||||
loadError.value = error.message || "Okänt fel vid laddning";
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user