feat(i18n): integrate translations in app.js

- Import and initialize i18n module
- Add language toggle button handler
- Replace hardcoded strings with t() function calls
- Update dynamic text (progress, success messages, etc.)
This commit is contained in:
2025-12-30 15:10:44 +01:00
parent 0570453a25
commit ffee16a3d4

View File

@@ -2,6 +2,7 @@ import { LessonEngine } from "./impl/LessonEngine.js";
import { CodeEditor } from "./impl/CodeEditor.js"; import { CodeEditor } from "./impl/CodeEditor.js";
import { renderLesson, renderModuleList, renderLevelIndicator, updateActiveLessonInSidebar } from "./helpers/renderer.js"; import { renderLesson, renderModuleList, renderLevelIndicator, updateActiveLessonInSidebar } from "./helpers/renderer.js";
import { loadModules } from "./config/lessons.js"; import { loadModules } from "./config/lessons.js";
import { initI18n, t, getLanguage, setLanguage, applyTranslations } from "./i18n.js";
// Simplified state - LessonEngine now manages lesson state and progress // Simplified state - LessonEngine now manages lesson state and progress
const state = { const state = {
@@ -15,6 +16,7 @@ const state = {
const elements = { const elements = {
// Header // Header
menuBtn: document.getElementById("menu-btn"), menuBtn: document.getElementById("menu-btn"),
langBtn: document.getElementById("lang-btn"),
helpBtn: document.getElementById("help-btn"), helpBtn: document.getElementById("help-btn"),
// Left panel // Left panel
@@ -100,15 +102,30 @@ function toggleExpectedResult() {
if (state.showExpected) { if (state.showExpected) {
elements.expectedOverlay.classList.add("visible"); elements.expectedOverlay.classList.add("visible");
elements.showExpectedBtn.textContent = "Hide Expected"; elements.showExpectedBtn.textContent = t("hideExpected");
elements.showExpectedBtn.classList.add("btn-primary"); elements.showExpectedBtn.classList.add("btn-primary");
} else { } else {
elements.expectedOverlay.classList.remove("visible"); elements.expectedOverlay.classList.remove("visible");
elements.showExpectedBtn.textContent = "Show Expected"; elements.showExpectedBtn.textContent = t("showExpected");
elements.showExpectedBtn.classList.remove("btn-primary"); elements.showExpectedBtn.classList.remove("btn-primary");
} }
} }
// ================= LANGUAGE TOGGLE =================
function toggleLanguage() {
const currentLang = getLanguage();
const newLang = currentLang === "en" ? "de" : "en";
setLanguage(newLang);
applyTranslations();
updateProgressDisplay();
// Reload current lesson to update any dynamic text
const engineState = lessonEngine.getCurrentState();
if (engineState.lesson) {
loadCurrentLesson();
}
}
// ================= HINT SYSTEM ================= // ================= HINT SYSTEM =================
function showHint(message, step, total, isSuccess = false) { function showHint(message, step, total, isSuccess = false) {
@@ -139,7 +156,11 @@ function showSuccessHint(message) {
function updateProgressDisplay() { function updateProgressDisplay() {
const stats = lessonEngine.getProgressStats(); const stats = lessonEngine.getProgressStats();
elements.progressFill.style.width = `${stats.percentComplete}%`; elements.progressFill.style.width = `${stats.percentComplete}%`;
elements.progressText.textContent = `${stats.percentComplete}% Complete (${stats.totalCompleted}/${stats.totalLessons})`; elements.progressText.textContent = t("progressText", {
percent: stats.percentComplete,
completed: stats.totalCompleted,
total: stats.totalLessons
});
} }
// ================= USER SETTINGS ================= // ================= USER SETTINGS =================
@@ -184,7 +205,7 @@ async function initializeModules() {
updateProgressDisplay(); updateProgressDisplay();
} catch (error) { } catch (error) {
console.error("Failed to load modules:", error); console.error("Failed to load modules:", error);
elements.lessonDescription.textContent = "Failed to load modules. Please refresh the page."; elements.lessonDescription.textContent = t("failedToLoad");
} }
} }
@@ -248,7 +269,7 @@ function updateEditorForMode(mode) {
cmMode: "html" cmMode: "html"
}, },
tailwind: { tailwind: {
placeholder: "Enter Tailwind classes (e.g., bg-blue-500 text-white p-4)", placeholder: t("tailwindPlaceholder"),
label: "Tailwind Classes", label: "Tailwind Classes",
cmMode: "css" cmMode: "css"
}, },
@@ -318,17 +339,17 @@ function loadCurrentLesson() {
// Update Run button text based on completion status // Update Run button text based on completion status
if (engineState.isCompleted) { if (engineState.isCompleted) {
elements.runBtn.innerHTML = '<img src="./gear.svg" alt="" />Re-run'; elements.runBtn.querySelector("span").textContent = t("rerun");
// Add completion badge if not present // Add completion badge if not present
if (!document.querySelector(".completion-badge")) { if (!document.querySelector(".completion-badge")) {
const badge = document.createElement("span"); const badge = document.createElement("span");
badge.className = "completion-badge"; badge.className = "completion-badge";
badge.textContent = "Completed"; badge.textContent = t("completed");
elements.lessonTitle.appendChild(badge); elements.lessonTitle.appendChild(badge);
} }
} else { } else {
elements.runBtn.innerHTML = '<img src="./gear.svg" alt="" />Run'; elements.runBtn.querySelector("span").textContent = t("run");
// Remove completion badge if exists // Remove completion badge if exists
const badge = document.querySelector(".completion-badge"); const badge = document.querySelector(".completion-badge");
@@ -448,17 +469,17 @@ function runCode() {
if (validationResult.isValid) { if (validationResult.isValid) {
// Show success hint // Show success hint
showSuccessHint(validationResult.message || "CRISPY! ٩(◕‿◕)۶ Your code works correctly."); showSuccessHint(validationResult.message || t("successMessage"));
// Update Run button // Update Run button
elements.runBtn.innerHTML = '<img src="./gear.svg" alt="" />Re-run'; elements.runBtn.querySelector("span").textContent = t("rerun");
elements.runBtn.classList.add("success"); elements.runBtn.classList.add("success");
// Add completion badge // Add completion badge
if (!document.querySelector(".completion-badge")) { if (!document.querySelector(".completion-badge")) {
const badge = document.createElement("span"); const badge = document.createElement("span");
badge.className = "completion-badge"; badge.className = "completion-badge";
badge.textContent = "Completed"; badge.textContent = t("completed");
elements.lessonTitle.appendChild(badge); elements.lessonTitle.appendChild(badge);
} }
@@ -486,7 +507,7 @@ function runCode() {
// Only show hints if enabled // Only show hints if enabled
if (!state.userSettings.disableFeedbackErrors) { if (!state.userSettings.disableFeedbackErrors) {
showHint(validationResult.message || "Keep trying!", step, total); showHint(validationResult.message || t("keepTrying"), step, total);
} }
} }
} }
@@ -546,6 +567,9 @@ function initCodeEditor() {
} }
function init() { function init() {
// Initialize i18n before anything else
initI18n();
loadUserSettings(); loadUserSettings();
// Initialize CodeMirror editor // Initialize CodeMirror editor
@@ -559,6 +583,9 @@ function init() {
elements.closeSidebar.addEventListener("click", closeSidebar); elements.closeSidebar.addEventListener("click", closeSidebar);
elements.sidebarBackdrop.addEventListener("click", closeSidebar); elements.sidebarBackdrop.addEventListener("click", closeSidebar);
// Language toggle
elements.langBtn.addEventListener("click", toggleLanguage);
// Expected result toggle // Expected result toggle
elements.showExpectedBtn.addEventListener("click", toggleExpectedResult); elements.showExpectedBtn.addEventListener("click", toggleExpectedResult);