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:
51
src/app.js
51
src/app.js
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user