forked from izu/student-web-if-development-kit
Optimize images and convert PNG to WebP
This commit is contained in:
@@ -1,3 +1,29 @@
|
||||
/**
|
||||
* localization.js — HarusSelesaiKP
|
||||
*
|
||||
* ANTI-FLICKER STRATEGY:
|
||||
* 1. IIFE `initLanguage()` runs SYNCHRONOUSLY (no defer/async) to set
|
||||
* `window.__currentLang` before the browser paints any content.
|
||||
* 2. HTML body carries `lang-pending` class; body is hidden via CSS until
|
||||
* `applyTranslations()` fires on DOMContentLoaded and removes the class.
|
||||
* 3. `languageChanged` CustomEvent signals dynamic sections (Facilities,
|
||||
* Campus, Culinary, LivingCost) to re-render in the new language.
|
||||
*/
|
||||
|
||||
// ─── 1. Determine language SYNCHRONOUSLY (before first paint) ────────────────
|
||||
(function initLanguage() {
|
||||
try {
|
||||
const saved = localStorage.getItem("lang");
|
||||
const browserLang = navigator.language?.startsWith("id") ? "id" : "en";
|
||||
window.__currentLang = saved || browserLang;
|
||||
} catch (e) {
|
||||
window.__currentLang = "id";
|
||||
}
|
||||
// Stamp <html lang> immediately so screen readers get the right language
|
||||
document.documentElement.lang = window.__currentLang;
|
||||
})();
|
||||
|
||||
// ─── 2. Translation data ─────────────────────────────────────────────────────
|
||||
const translations = {
|
||||
id: {
|
||||
// Kelompok HarusSelesaiKP (skp)
|
||||
@@ -330,3 +356,76 @@ const translations = {
|
||||
skp_cost_type_transport: "Transport",
|
||||
},
|
||||
};
|
||||
|
||||
// ─── 3. Public translation helper ────────────────────────────────────────────
|
||||
/**
|
||||
* t(key) — returns translated string for the active language.
|
||||
* Falls back to Indonesian if key is missing in the active language.
|
||||
*/
|
||||
function t(key) {
|
||||
const lang = window.__currentLang || "id";
|
||||
return translations[lang]?.[key] ?? translations["id"]?.[key] ?? key;
|
||||
}
|
||||
|
||||
// ─── 4. Apply translations to all [data-i18n] elements ───────────────────────
|
||||
function applyTranslations(lang) {
|
||||
window.__currentLang = lang;
|
||||
document.documentElement.lang = lang;
|
||||
|
||||
try {
|
||||
localStorage.setItem("lang", lang);
|
||||
} catch (e) {
|
||||
// localStorage may be blocked (private mode, etc.) — fail silently
|
||||
}
|
||||
|
||||
document.querySelectorAll("[data-i18n]").forEach((el) => {
|
||||
const key = el.dataset.i18n;
|
||||
const text = t(key);
|
||||
if (text && text !== key) {
|
||||
el.textContent = text;
|
||||
}
|
||||
});
|
||||
|
||||
// Signal dynamic components to re-render
|
||||
document.dispatchEvent(new CustomEvent("languageChanged"));
|
||||
}
|
||||
|
||||
// ─── 5. Toggle language (called by UI buttons) ───────────────────────────────
|
||||
function toggleLanguage() {
|
||||
const next = window.__currentLang === "id" ? "en" : "id";
|
||||
applyTranslations(next);
|
||||
updateLanguageButtonUI(next);
|
||||
}
|
||||
|
||||
function updateLanguageButtonUI(lang) {
|
||||
document.querySelectorAll(".language-toggle-btn").forEach((btn) => {
|
||||
const idSpan = btn.querySelector(".lang-id");
|
||||
const enSpan = btn.querySelector(".lang-en");
|
||||
if (idSpan && enSpan) {
|
||||
if (lang === "id") {
|
||||
idSpan.className = "lang-id font-bold text-white";
|
||||
enSpan.className = "lang-en font-normal opacity-50";
|
||||
} else {
|
||||
idSpan.className = "lang-id font-normal opacity-50";
|
||||
enSpan.className = "lang-en font-bold text-white";
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ─── 6. Boot on DOMContentLoaded ─────────────────────────────────────────────
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
// Apply translations to all static [data-i18n] nodes
|
||||
applyTranslations(window.__currentLang);
|
||||
|
||||
// Sync language button label
|
||||
updateLanguageButtonUI(window.__currentLang);
|
||||
|
||||
// Wire up toggle buttons
|
||||
document.querySelectorAll(".language-toggle-btn").forEach((btn) => {
|
||||
btn.addEventListener("click", toggleLanguage);
|
||||
});
|
||||
|
||||
// ── Reveal body: remove anti-flicker class after translations applied ──
|
||||
document.body.classList.remove("lang-pending");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user