Add function Language
Some checks failed
Test / test (push) Has been cancelled

This commit is contained in:
2026-06-16 16:44:04 +07:00
parent 1156e1ab29
commit a2e87aeb29
11 changed files with 1790 additions and 474 deletions

View File

@@ -1,63 +1,14 @@
(() => {
const el = (id) => document.getElementById(id);
const I18N = {
vi: {
"topbar.allOk": "ỔN ĐỊNH",
"topbar.error": "LỖI",
"topbar.paused": "TẠM DỪNG",
"topbar.running": "ĐANG CHẠY",
"topbar.waiting": "Đang chờ mission mới…",
"topbar.noMissionsQueue": "Không có mission trong queue…",
"topbar.reset": "RESET",
"topbar.changeUserData": "Lưu thông tin",
"topbar.changePassword": "Đổi mật khẩu",
"topbar.logout": "Đăng xuất",
"topbar.displayName": "Tên hiển thị",
"topbar.reload": "Tải lại",
"topbar.saveLayout": "Lưu layout",
"topbar.joystickTitle": "Điều khiển tay (Joystick)",
"topbar.joystickSpeed": "Tốc độ",
"topbar.joystickOff": "Tắt joystick",
"topbar.localeVi": "TIẾNG VIỆT",
"topbar.localeEn": "ENGLISH",
"topbar.startHint": "Bấm để START robot",
"topbar.pauseHint": "Bấm để PAUSE robot",
"topbar.code": "Mã",
"topbar.module": "Module",
},
en: {
"topbar.allOk": "ALL OK",
"topbar.error": "ERROR",
"topbar.paused": "PAUSED",
"topbar.running": "RUNNING",
"topbar.waiting": "Waiting for new missions…",
"topbar.noMissionsQueue": "No missions in queue…",
"topbar.reset": "RESET",
"topbar.changeUserData": "Change user data",
"topbar.changePassword": "Change password",
"topbar.logout": "Log out",
"topbar.displayName": "Display name",
"topbar.reload": "Reload",
"topbar.saveLayout": "Save layout",
"topbar.joystickTitle": "Manual control (Joystick)",
"topbar.joystickSpeed": "Speed",
"topbar.joystickOff": "Disengage joystick",
"topbar.localeVi": "TIẾNG VIỆT",
"topbar.localeEn": "ENGLISH",
"topbar.startHint": "Click to START the robot",
"topbar.pauseHint": "Click to PAUSE the robot",
"topbar.code": "Code",
"topbar.module": "Module",
},
};
const LOCALE_META = {
vi: { flag: "🇻🇳", labelKey: "topbar.localeVi" },
en: { flag: "🇺🇸", labelKey: "topbar.localeEn" },
};
let locale = "vi";
const t = (key, vars) => window.I18n?.t(key, vars) ?? key;
const getLocale = () => window.I18n?.getLocale?.() ?? "vi";
let robotStatus = null;
let pollTimer = null;
let eventsBound = false;
@@ -67,8 +18,13 @@
let joystickRaf = null;
let lastCmd = { linear: 0, angular: 0 };
function t(key) {
return I18N[locale]?.[key] ?? I18N.en[key] ?? key;
function applyLocale(next) {
if (window.I18n) window.I18n.setLocale(next);
if (robotStatus) renderAll(robotStatus);
}
function loadLocale() {
/* locale owned by I18n */
}
function canSeeMissions() {
@@ -96,35 +52,6 @@
return data;
}
function applyLocale(next) {
locale = LOCALE_META[next] ? next : "vi";
try {
localStorage.setItem("lm_locale", locale);
} catch {
/* ignore */
}
document.documentElement.lang = locale;
document.querySelectorAll("[data-i18n]").forEach((node) => {
const key = node.dataset.i18n;
if (key) node.textContent = t(key);
});
const meta = LOCALE_META[locale];
if (el("mirLocaleFlag")) el("mirLocaleFlag").textContent = meta.flag;
if (el("mirLocaleLabel")) el("mirLocaleLabel").textContent = t(meta.labelKey);
window.dispatchEvent(new CustomEvent("lm:locale-change", { detail: { locale } }));
if (robotStatus) renderAll(robotStatus);
}
function loadLocale() {
try {
const saved = localStorage.getItem("lm_locale");
if (saved && LOCALE_META[saved]) locale = saved;
} catch {
/* ignore */
}
applyLocale(locale);
}
function closePanels() {
document.querySelectorAll(".mirPanel").forEach((p) => {
p.hidden = true;
@@ -226,7 +153,7 @@
bodyEl.innerHTML = `
<div class="mirStatusOkTitle">${t("topbar.allOk")}</div>
<div class="mirStatusDesc">${message}</div>
${status.queue_pending > 0 ? `<div class="mirStatusMeta">${status.queue_pending} mission(s) in queue</div>` : ""}`;
${status.queue_pending > 0 ? `<div class="mirStatusMeta">${t("topbar.queueCount", { n: status.queue_pending })}</div>` : ""}`;
if (footerEl) footerEl.hidden = true;
}
}
@@ -267,7 +194,10 @@
joystickActive = engaged;
const speedSel = el("joystickSpeedSelect");
if (speedSel && status.joystick_speed) speedSel.value = status.joystick_speed;
if (el("joystickSpeedLabel")) el("joystickSpeedLabel").textContent = status.joystick_speed || "fast";
if (el("joystickSpeedLabel")) {
const speed = status.joystick_speed || "fast";
el("joystickSpeedLabel").textContent = t(`topbar.joystickSpeed.${speed}`);
}
}
function renderAll(status) {
@@ -438,7 +368,7 @@
el("mirSegJoystick")?.addEventListener("click", async () => {
if (!canControl()) {
alert(locale === "vi" ? "Không có quyền điều khiển" : "No control permission");
alert(t("topbar.noControlPermission"));
return;
}
try {
@@ -472,6 +402,9 @@
});
bindJoystickPad();
window.addEventListener("lm:locale-change", () => {
if (robotStatus) renderAll(robotStatus);
});
}
function start() {
@@ -502,7 +435,7 @@
window.TopbarApp = {
t,
getLocale: () => locale,
getLocale,
applyLocale,
refresh: fetchStatus,
getRobotStatus: () => robotStatus,