Added translations and data attributes for almost all user-facing text
This commit is contained in:
@@ -7,6 +7,9 @@
|
||||
- main.js added Dark & Light mode i18n.js keys.
|
||||
- New Admin section Header Settings to change Header Title.
|
||||
- Admin Panel confirm unsaved changes.
|
||||
- Added translations and data attributes for almost all user-facing text
|
||||
|
||||
---
|
||||
|
||||
## Changes 4/12/2025
|
||||
|
||||
|
||||
16
js/auth.js
16
js/auth.js
@@ -1,5 +1,5 @@
|
||||
import { sendRequest } from './networkUtils.js';
|
||||
import { t } from './i18n.js';
|
||||
import { t, applyTranslations } from './i18n.js';
|
||||
import {
|
||||
toggleVisibility,
|
||||
showToast as originalShowToast,
|
||||
@@ -164,7 +164,8 @@ function updateAuthenticatedUI(data) {
|
||||
restoreBtn = document.createElement("button");
|
||||
restoreBtn.id = "restoreFilesBtn";
|
||||
restoreBtn.classList.add("btn", "btn-warning");
|
||||
restoreBtn.innerHTML = '<i class="material-icons" title="Restore/Delete Trash">restore_from_trash</i>';
|
||||
restoreBtn.setAttribute("data-i18n-title", "trash_restore_delete");
|
||||
restoreBtn.innerHTML = '<i class="material-icons">restore_from_trash</i>';
|
||||
if (firstButton) insertAfter(restoreBtn, firstButton);
|
||||
else headerButtons.appendChild(restoreBtn);
|
||||
}
|
||||
@@ -175,7 +176,8 @@ function updateAuthenticatedUI(data) {
|
||||
adminPanelBtn = document.createElement("button");
|
||||
adminPanelBtn.id = "adminPanelBtn";
|
||||
adminPanelBtn.classList.add("btn", "btn-info");
|
||||
adminPanelBtn.innerHTML = '<i class="material-icons" title="Admin Panel">admin_panel_settings</i>';
|
||||
adminPanelBtn.setAttribute("data-i18n-title", "admin_panel");
|
||||
adminPanelBtn.innerHTML = '<i class="material-icons">admin_panel_settings</i>';
|
||||
insertAfter(adminPanelBtn, restoreBtn);
|
||||
adminPanelBtn.addEventListener("click", openAdminPanel);
|
||||
} else {
|
||||
@@ -194,17 +196,19 @@ function updateAuthenticatedUI(data) {
|
||||
userPanelBtn = document.createElement("button");
|
||||
userPanelBtn.id = "userPanelBtn";
|
||||
userPanelBtn.classList.add("btn", "btn-user");
|
||||
userPanelBtn.innerHTML = '<i class="material-icons" title="User Panel">account_circle</i>';
|
||||
userPanelBtn.setAttribute("data-i18n-title", "user_panel");
|
||||
userPanelBtn.innerHTML = '<i class="material-icons">account_circle</i>';
|
||||
|
||||
const adminBtn = document.getElementById("adminPanelBtn");
|
||||
if (adminBtn) insertAfter(userPanelBtn, adminBtn);
|
||||
else if (firstButton) insertAfter(userPanelBtn, firstButton);
|
||||
else headerButtons.appendChild(userPanelBtn);
|
||||
else headerButtons.appendChild(userPanelBtn);
|
||||
userPanelBtn.addEventListener("click", openUserPanel);
|
||||
} else {
|
||||
userPanelBtn.style.display = "block";
|
||||
}
|
||||
}
|
||||
|
||||
applyTranslations();
|
||||
updateItemsPerPageSelect();
|
||||
updateLoginOptionsUIFromStorage();
|
||||
}
|
||||
|
||||
@@ -811,7 +811,7 @@ export function openAdminPanel() {
|
||||
|
||||
export async function closeAdminPanel() {
|
||||
if (hasUnsavedChanges()) {
|
||||
const userConfirmed = await showCustomConfirmModal("You have unsaved changes. Are you sure you want to close without saving?");
|
||||
const userConfirmed = await showCustomConfirmModal(t("unsaved_changes_confirm"));
|
||||
if (!userConfirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -117,9 +117,9 @@ export function buildSearchAndPaginationControls({ currentPage, totalPages, sear
|
||||
</div>
|
||||
<div class="col-12 col-md-4 text-left">
|
||||
<div class="d-flex justify-content-center justify-content-md-start align-items-center">
|
||||
<button class="custom-prev-next-btn" ${currentPage === 1 ? "disabled" : ""} onclick="changePage(${currentPage - 1})">Prev</button>
|
||||
<span class="page-indicator">Page ${currentPage} of ${totalPages || 1}</span>
|
||||
<button class="custom-prev-next-btn" ${currentPage === totalPages ? "disabled" : ""} onclick="changePage(${currentPage + 1})">Next</button>
|
||||
<button class="custom-prev-next-btn" ${currentPage === 1 ? "disabled" : ""} onclick="changePage(${currentPage - 1})">${t("prev")}</button>
|
||||
<span class="page-indicator">${t("page")} ${currentPage} ${t("of")} ${totalPages || 1}</span>
|
||||
<button class="custom-prev-next-btn" ${currentPage === totalPages ? "disabled" : ""} onclick="changePage(${currentPage + 1})">${t("next")}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -137,7 +137,7 @@ export function buildFileTableHeader(sortOrder) {
|
||||
<th data-column="uploaded" class="hide-small hide-medium sortable-col">${t("upload_date")} ${sortOrder.column === "uploaded" ? (sortOrder.ascending ? "▲" : "▼") : ""}</th>
|
||||
<th data-column="size" class="hide-small sortable-col">${t("file_size")} ${sortOrder.column === "size" ? (sortOrder.ascending ? "▲" : "▼") : ""}</th>
|
||||
<th data-column="uploader" class="hide-small hide-medium sortable-col">${t("uploader")} ${sortOrder.column === "uploader" ? (sortOrder.ascending ? "▲" : "▼") : ""}</th>
|
||||
<th>Actions</th>
|
||||
<th>${t("actions")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
`;
|
||||
@@ -181,36 +181,38 @@ export function buildFileTableRow(file, folderPath) {
|
||||
<div class="button-wrap" style="display: flex; justify-content: left; gap: 5px;">
|
||||
<button type="button" class="btn btn-sm btn-success download-btn"
|
||||
onclick="openDownloadModal('${file.name}', '${file.folder || 'root'}')"
|
||||
title="Download">
|
||||
<i class="material-icons">file_download</i>
|
||||
title="${t('download')}">
|
||||
<i class="material-icons">file_download</i>
|
||||
</button>
|
||||
${file.editable ? `
|
||||
<button class="btn btn-sm edit-btn"
|
||||
onclick='editFile(${JSON.stringify(file.name)}, ${JSON.stringify(file.folder || "root")})'
|
||||
title="Edit">
|
||||
title="${t('edit')}">
|
||||
<i class="material-icons">edit</i>
|
||||
</button>
|
||||
` : ""}
|
||||
${previewButton}
|
||||
<button class="btn btn-sm btn-warning rename-btn"
|
||||
onclick='renameFile(${JSON.stringify(file.name)}, ${JSON.stringify(file.folder || "root")})'
|
||||
title="Rename">
|
||||
title="${t('rename')}">
|
||||
<i class="material-icons">drive_file_rename_outline</i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
`;
|
||||
}
|
||||
|
||||
export function buildBottomControls(itemsPerPageSetting) {
|
||||
return `
|
||||
<div class="d-flex align-items-center mt-3 bottom-controls">
|
||||
<label class="label-inline mr-2 mb-0">Show</label>
|
||||
<label class="label-inline mr-2 mb-0">${t("show")}</label>
|
||||
<select class="form-control bottom-select" onchange="changeItemsPerPage(this.value)">
|
||||
${[10, 20, 50, 100].map(num => `<option value="${num}" ${num === itemsPerPageSetting ? "selected" : ""}>${num}</option>`).join("")}
|
||||
${[10, 20, 50, 100]
|
||||
.map(num => `<option value="${num}" ${num === itemsPerPageSetting ? "selected" : ""}>${num}</option>`)
|
||||
.join("")}
|
||||
</select>
|
||||
<span class="items-per-page-text ml-2 mb-0">items per page</span>
|
||||
<span class="items-per-page-text ml-2 mb-0">${t("items_per_page")}</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ function buildFolderSummary(filteredFiles) {
|
||||
return sum + parseSizeToBytes(file.size);
|
||||
}, 0);
|
||||
const sizeStr = formatSize(totalBytes);
|
||||
return `<strong>Total Files:</strong> ${totalFiles} | <strong>Total Size:</strong> ${sizeStr}`;
|
||||
return `<strong>${t('total_files')}:</strong> ${totalFiles} | <strong>${t('total_size')}:</strong> ${sizeStr}`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -316,7 +316,7 @@ export function renderFileTable(folder, container) {
|
||||
rowHTML = rowHTML.replace(/(<td class="file-name-cell">)(.*?)(<\/td>)/, (match, p1, p2, p3) => {
|
||||
return p1 + p2 + tagBadgesHTML + p3;
|
||||
});
|
||||
rowHTML = rowHTML.replace(/(<\/div>\s*<\/td>\s*<\/tr>)/, `<button class="share-btn btn btn-sm btn-secondary" data-file="${escapeHTML(file.name)}" title="Share">
|
||||
rowHTML = rowHTML.replace(/(<\/div>\s*<\/td>\s*<\/tr>)/, `<button class="share-btn btn btn-sm btn-secondary" data-file="${escapeHTML(file.name)}" title="${t('share')}">
|
||||
<i class="material-icons">share</i>
|
||||
</button>$1`);
|
||||
rowsHTML += rowHTML;
|
||||
@@ -425,18 +425,18 @@ export function renderGalleryView(folder, container) {
|
||||
<div class="button-wrap" style="display: flex; justify-content: center; gap: 5px;">
|
||||
<button type="button" class="btn btn-sm btn-success download-btn"
|
||||
onclick="openDownloadModal('${file.name}', '${file.folder || 'root'}')"
|
||||
title="Download">
|
||||
title="${t('download')}">
|
||||
<i class="material-icons">file_download</i>
|
||||
</button>
|
||||
${file.editable ? `
|
||||
<button class="btn btn-sm edit-btn" onclick='editFile(${JSON.stringify(file.name)}, ${JSON.stringify(file.folder || "root")})' title="Edit">
|
||||
<button class="btn btn-sm edit-btn" onclick='editFile(${JSON.stringify(file.name)}, ${JSON.stringify(file.folder || "root")})' title="${t('Edit')}">
|
||||
<i class="material-icons">edit</i>
|
||||
</button>
|
||||
` : ""}
|
||||
<button class="btn btn-sm btn-warning rename-btn" onclick='renameFile(${JSON.stringify(file.name)}, ${JSON.stringify(file.folder || "root")})' title="Rename">
|
||||
<button class="btn btn-sm btn-warning rename-btn" onclick='renameFile(${JSON.stringify(file.name)}, ${JSON.stringify(file.folder || "root")})' title="${t('rename')}">
|
||||
<i class="material-icons">drive_file_rename_outline</i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-secondary share-btn" data-file="${escapeHTML(file.name)}" title="Share">
|
||||
<button class="btn btn-sm btn-secondary share-btn" data-file="${escapeHTML(file.name)}" title="${t('share')}">
|
||||
<i class="material-icons">share</i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
30
js/i18n.js
30
js/i18n.js
@@ -85,6 +85,7 @@ const translations = {
|
||||
"folder_help_item_4": "To rename or delete a folder, select it and then click the appropriate button.",
|
||||
|
||||
// File List keys:
|
||||
"actions": "Actions",
|
||||
"file_list_title": "Files in (Root)",
|
||||
"files_in": "Files in",
|
||||
"delete_files": "Delete Files",
|
||||
@@ -101,6 +102,13 @@ const translations = {
|
||||
"download_zip_title": "Download Selected Files as Zip",
|
||||
"download_zip_prompt": "Enter a name for the zip file:",
|
||||
"zip_placeholder": "files.zip",
|
||||
"share": "Share",
|
||||
"total_files": "Total Files",
|
||||
"total_size": "Total Size",
|
||||
"prev": "Prev",
|
||||
"next": "Next",
|
||||
"page": "Page",
|
||||
"of": "of",
|
||||
|
||||
// Login Form keys:
|
||||
"login": "Login",
|
||||
@@ -142,6 +150,7 @@ const translations = {
|
||||
// Custom Confirm Modal keys:
|
||||
"yes": "Yes",
|
||||
"no": "No",
|
||||
"unsaved_changes_confirm": "You have unsaved changes. Are you sure you want to close without saving?",
|
||||
"delete": "Delete",
|
||||
"download": "Download",
|
||||
"upload": "Upload",
|
||||
@@ -164,6 +173,7 @@ const translations = {
|
||||
// NEW KEYS ADDED FOR ADMIN, USER PANELS, AND TOTP MODALS:
|
||||
"admin_panel": "Admin Panel",
|
||||
"user_panel": "User Panel",
|
||||
"trash_restore_delete": "Trash Restore/Delete",
|
||||
"totp_settings": "TOTP Settings",
|
||||
"enable_totp": "Enable TOTP",
|
||||
"language": "Language",
|
||||
@@ -217,7 +227,9 @@ const translations = {
|
||||
"save_permissions": "Save Permissions",
|
||||
"your_recovery_code": "Your Recovery Code",
|
||||
"please_save_recovery_code": "Please save this code securely. It will not be shown again and can only be used once.",
|
||||
"ok": "OK"
|
||||
"ok": "OK",
|
||||
"show": "Show",
|
||||
"items_per_page": "items per page"
|
||||
},
|
||||
es: {
|
||||
"please_log_in_to_continue": "Por favor, inicie sesión para continuar.",
|
||||
@@ -361,6 +373,7 @@ const translations = {
|
||||
// Custom Confirm Modal keys:
|
||||
"yes": "Sí",
|
||||
"no": "No",
|
||||
"unsaved_changes_confirm": "Tiene cambios sin guardar. ¿Está seguro de que desea cerrar sin guardar?",
|
||||
"delete": "Eliminar",
|
||||
"download": "Descargar",
|
||||
"upload": "Cargar",
|
||||
@@ -580,6 +593,7 @@ const translations = {
|
||||
// Custom Confirm Modal keys:
|
||||
"yes": "Oui",
|
||||
"no": "Non",
|
||||
"unsaved_changes_confirm": "Vous avez des modifications non enregistrées. Êtes-vous sûr de vouloir fermer sans enregistrer ?",
|
||||
"delete": "Supprimer",
|
||||
"download": "Télécharger",
|
||||
"upload": "Téléverser",
|
||||
@@ -742,6 +756,7 @@ const translations = {
|
||||
"folder_help_item_4": "Um einen Ordner umzubenennen oder zu löschen, wählen Sie ihn aus und klicken Sie auf den entsprechenden Button.",
|
||||
|
||||
// File List keys:
|
||||
"actions": "Aktionen",
|
||||
"file_list_title": "Dateien in (Root)",
|
||||
"files_in": "Dateien in",
|
||||
"delete_files": "Dateien löschen",
|
||||
@@ -758,6 +773,13 @@ const translations = {
|
||||
"download_zip_title": "Ausgewählte Dateien als Zip herunterladen",
|
||||
"download_zip_prompt": "Geben Sie einen Namen für die Zip-Datei ein:",
|
||||
"zip_placeholder": "files.zip",
|
||||
"share": "Teilen",
|
||||
"total_files": "Gesamtanzahl",
|
||||
"total_size": "Gesamtgröße",
|
||||
"prev": "Zurück",
|
||||
"next": "Weiter",
|
||||
"page": "Seite",
|
||||
"of": "von",
|
||||
|
||||
// Login Form keys:
|
||||
"login": "Anmelden",
|
||||
@@ -799,6 +821,7 @@ const translations = {
|
||||
// Custom Confirm Modal keys:
|
||||
"yes": "Ja",
|
||||
"no": "Nein",
|
||||
"unsaved_changes_confirm": "Sie haben ungespeicherte Änderungen. Sind Sie sicher, dass Sie schließen möchten, ohne zu speichern?",
|
||||
"delete": "Löschen",
|
||||
"download": "Herunterladen",
|
||||
"upload": "Hochladen",
|
||||
@@ -821,6 +844,7 @@ const translations = {
|
||||
// NEW KEYS ADDED FOR ADMIN, USER PANELS, AND TOTP MODALS:
|
||||
"admin_panel": "Administrationsbereich",
|
||||
"user_panel": "Benutzerbereich",
|
||||
"trash_restore_delete": "Papierkorb wiederherstellen/löschen",
|
||||
"totp_settings": "TOTP-Einstellungen",
|
||||
"enable_totp": "TOTP aktivieren",
|
||||
"language": "Sprache",
|
||||
@@ -874,7 +898,9 @@ const translations = {
|
||||
"save_permissions": "Berechtigungen speichern",
|
||||
"your_recovery_code": "Ihr Wiederherstellungscode",
|
||||
"please_save_recovery_code": "Bitte speichern Sie diesen Code sicher. Er wird nicht erneut angezeigt und kann nur einmal verwendet werden.",
|
||||
"ok": "OK"
|
||||
"ok": "OK",
|
||||
"show": "Zeige",
|
||||
"items_per_page": "elemente pro seite"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user